<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  <title>CoffeeScript Test Suite</title>
  <script src="browser-compiler/coffee-script.js"></script>
  <script src="https://cdn.jsdelivr.net/underscorejs/1.8.3/underscore-min.js"></script>
  <style>
    body, pre {
      font-family: Consolas, Menlo, Monaco, monospace;
    }
    body {
      margin: 1em;
    }
    h1 {
      font-size: 1.3em;
    }
    div {
      margin: 0.6em;
    }
    .good {
      color: #22b24c
    }
    .bad {
      color: #eb6864
    }
    .subtle {
      font-size: 0.7em;
      color: #999999
    }
  </style>
</head>
<body>

<h1>CoffeeScript Test Suite</h1>

<pre id="stdout"></pre>

<script type="text/coffeescript">
@testingBrowser = yes
@global = window
stdout  = document.getElementById 'stdout'
start   = new Date
success = total = done = failed = 0

say = (msg, className) ->
  div = document.createElement 'div'
  div.className = className if className?
  div.appendChild document.createTextNode msg
  stdout.appendChild div
  msg

@test = (description, fn) ->
  ++total
  try
    fn.call(fn)
    ++success
  catch exception
    say "#{description}:", 'bad'
    say fn.toString(), 'subtle' if fn.toString?
    say exception, 'bad'
    console.error exception

@ok = (good, msg = 'Error') ->
  throw Error msg unless good

# Polyfill Node assert's fail
@fail = ->
  ok no

# Polyfill Node assert's deepEqual with Underscore's isEqual
@deepEqual = (a, b) ->
  ok _.isEqual(a, b), "Expected #{JSON.stringify a} to deep equal #{JSON.stringify b}"

# See http://wiki.ecmascript.org/doku.php?id=harmony:egal
egal = (a, b) ->
  if a is b
    a isnt 0 or 1/a is 1/b
  else
    a isnt a and b isnt b

# A recursive functional equivalence helper; uses egal for testing equivalence.
arrayEgal = (a, b) ->
  if egal a, b then yes
  else if a instanceof Array and b instanceof Array
    return no unless a.length is b.length
    return no for el, idx in a when not arrayEgal el, b[idx]
    yes

@eq      = (a, b, msg) -> ok egal(a, b), msg or "Expected #{a} to equal #{b}"
@arrayEq = (a, b, msg) -> ok arrayEgal(a,b), msg or "Expected #{a} to deep equal #{b}"

@toJS = (str) ->
  CoffeeScript.compile str, bare: yes
  .replace /^\s+|\s+$/g, '' # Trim leading/trailing whitespace


@doesNotThrow = (fn) ->
  fn()
  ok yes

@throws = (fun, err, msg) ->
  try
    fun()
  catch e
    if err
      if typeof err is 'function' and e instanceof err # Handle comparing exceptions
        ok yes
      else if e.toString().indexOf('[stdin]') is 0 # Handle comparing error messages
        ok err e
      else
        eq e, err
    else
      ok yes
    return
  ok no


# Run the tests
for test in document.getElementsByClassName 'test'
  say '\u2714 ' + test.id
  options = {}
  options.literate = yes if test.type is 'text/x-literate-coffeescript'
  CoffeeScript.run test.innerHTML, options

# Finish up
yay = success is total and not failed
sec = (new Date - start) / 1000
msg = "passed #{success} tests in #{ sec.toFixed 2 } seconds"
msg = "failed #{ total - success } tests and #{msg}" unless yay
say msg, (if yay then 'good' else 'bad')
</script>

<script type="text/x-coffeescript" class="test" id="arrays">
# Array Literals
# --------------

# * Array Literals
# * Splats in Array Literals

# TODO: add indexing and method invocation tests: [1][0] is 1, [].toString()

test "trailing commas", ->
  trailingComma = [1, 2, 3,]
  ok (trailingComma[0] is 1) and (trailingComma[2] is 3) and (trailingComma.length is 3)

  trailingComma = [
    1, 2, 3,
    4, 5, 6
    7, 8, 9,
  ]
  (sum = (sum or 0) + n) for n in trailingComma

  a = [((x) -> x), ((x) -> x * x)]
  ok a.length is 2

test "incorrect indentation without commas", ->
  result = [['a']
   {b: 'c'}]
  ok result[0][0] is 'a'
  ok result[1]['b'] is 'c'


# Splats in Array Literals

test "array splat expansions with assignments", ->
  nums = [1, 2, 3]
  list = [a = 0, nums..., b = 4]
  eq 0, a
  eq 4, b
  arrayEq [0,1,2,3,4], list


test "mixed shorthand objects in array lists", ->

  arr = [
    a:1
    'b'
    c:1
  ]
  ok arr.length is 3
  ok arr[2].c is 1

  arr = [b: 1, a: 2, 100]
  eq arr[1], 100

  arr = [a:0, b:1, (1 + 1)]
  eq arr[1], 2

  arr = [a:1, 'a', b:1, 'b']
  eq arr.length, 4
  eq arr[2].b, 1
  eq arr[3], 'b'


test "array splats with nested arrays", ->
  nonce = {}
  a = [nonce]
  list = [1, 2, a...]
  eq list[0], 1
  eq list[2], nonce

  a = [[nonce]]
  list = [1, 2, a...]
  arrayEq list, [1, 2, [nonce]]

test "#1274: `[] = a()` compiles to `false` instead of `a()`", ->
  a = false
  fn = -> a = true
  [] = fn()
  ok a

test "#3194: string interpolation in array", ->
  arr = [ "a"
          key: 'value'
        ]
  eq 2, arr.length
  eq 'a', arr[0]
  eq 'value', arr[1].key

  b = 'b'
  arr = [ "a#{b}"
          key: 'value'
        ]
  eq 2, arr.length
  eq 'ab', arr[0]
  eq 'value', arr[1].key

test "regex interpolation in array", ->
  arr = [ /a/
          key: 'value'
        ]
  eq 2, arr.length
  eq 'a', arr[0].source
  eq 'value', arr[1].key

  b = 'b'
  arr = [ ///a#{b}///
          key: 'value'
        ]
  eq 2, arr.length
  eq 'ab', arr[0].source
  eq 'value', arr[1].key


test "for-from loops over Array", ->
  array1 = [50, 30, 70, 20]
  array2 = []
  for x from array1
    array2.push(x)
  arrayEq array1, array2

  array1 = [[20, 30], [40, 50]]
  array2 = []
  for [a, b] from array1
    array2.push(b)
    array2.push(a)
  arrayEq array2, [30, 20, 50, 40]

  array1 = [{a: 10, b: 20, c: 30}, {a: 40, b: 50, c: 60}]
  array2 = []
  for {a: a, b, c: d} from array1
    array2.push([a, b, d])
  arrayEq array2, [[10, 20, 30], [40, 50, 60]]

  array1 = [[10, 20, 30, 40, 50]]
  for [a, b..., c] from array1
    eq 10, a
    arrayEq [20, 30, 40], b
    eq 50, c

test "for-from comprehensions over Array", ->
  array1 = (x + 10 for x from [10, 20, 30])
  ok array1.join(' ') is '20 30 40'

  array2 = (x for x from [30, 41, 57] when x %% 3 is 0)
  ok array2.join(' ') is '30 57'

  array1 = (b + 5 for [a, b] from [[20, 30], [40, 50]])
  ok array1.join(' ') is '35 55'

  array2 = (a + b for [a, b] from [[10, 20], [30, 40], [50, 60]] when a + b >= 70)
  ok array2.join(' ') is '70 110'

</script>
<script type="text/x-coffeescript" class="test" id="assignment">
# Assignment
# ----------

# * Assignment
# * Compound Assignment
# * Destructuring Assignment
# * Context Property (@) Assignment
# * Existential Assignment (?=)
# * Assignment to variables similar to generated variables

test "context property assignment (using @)", ->
  nonce = {}
  addMethod = ->
    @method = -> nonce
    this
  eq nonce, addMethod.call({}).method()

test "unassignable values", ->
  nonce = {}
  for nonref in ['', '""', '0', 'f()'].concat CoffeeScript.RESERVED
    eq nonce, (try CoffeeScript.compile "#{nonref} = v" catch e then nonce)

# Compound Assignment

test "boolean operators", ->
  nonce = {}

  a  = 0
  a or= nonce
  eq nonce, a

  b  = 1
  b or= nonce
  eq 1, b

  c = 0
  c and= nonce
  eq 0, c

  d = 1
  d and= nonce
  eq nonce, d

  # ensure that RHS is treated as a group
  e = f = false
  e and= f or true
  eq false, e

test "compound assignment as a sub expression", ->
  [a, b, c] = [1, 2, 3]
  eq 6, (a + b += c)
  eq 1, a
  eq 5, b
  eq 3, c

# *note: this test could still use refactoring*
test "compound assignment should be careful about caching variables", ->
  count = 0
  list = []

  list[++count] or= 1
  eq 1, list[1]
  eq 1, count

  list[++count] ?= 2
  eq 2, list[2]
  eq 2, count

  list[count++] and= 6
  eq 6, list[2]
  eq 3, count

  base = ->
    ++count
    base

  base().four or= 4
  eq 4, base.four
  eq 4, count

  base().five ?= 5
  eq 5, base.five
  eq 5, count

  eq 5, base().five ?= 6
  eq 6, count

test "compound assignment with implicit objects", ->
  obj = undefined
  obj ?=
    one: 1

  eq 1, obj.one

  obj and=
    two: 2

  eq undefined, obj.one
  eq         2, obj.two

test "compound assignment (math operators)", ->
  num = 10
  num -= 5
  eq 5, num

  num *= 10
  eq 50, num

  num /= 10
  eq 5, num

  num %= 3
  eq 2, num

test "more compound assignment", ->
  a = {}
  val = undefined
  val ||= a
  val ||= true
  eq a, val

  b = {}
  val &&= true
  eq val, true
  val &&= b
  eq b, val

  c = {}
  val = null
  val ?= c
  val ?= true
  eq c, val

test "#1192: assignment starting with object literals", ->
  doesNotThrow (-> CoffeeScript.run "{}.p = 0")
  doesNotThrow (-> CoffeeScript.run "{}.p++")
  doesNotThrow (-> CoffeeScript.run "{}[0] = 1")
  doesNotThrow (-> CoffeeScript.run """{a: 1, 'b', "#{1}": 2}.p = 0""")
  doesNotThrow (-> CoffeeScript.run "{a:{0:{}}}.a[0] = 0")


# Destructuring Assignment

test "empty destructuring assignment", ->
  {} = [] = undefined

test "chained destructuring assignments", ->
  [a] = {0: b} = {'0': c} = [nonce={}]
  eq nonce, a
  eq nonce, b
  eq nonce, c

test "variable swapping to verify caching of RHS values when appropriate", ->
  a = nonceA = {}
  b = nonceB = {}
  c = nonceC = {}
  [a, b, c] = [b, c, a]
  eq nonceB, a
  eq nonceC, b
  eq nonceA, c
  [a, b, c] = [b, c, a]
  eq nonceC, a
  eq nonceA, b
  eq nonceB, c
  fn = ->
    [a, b, c] = [b, c, a]
  arrayEq [nonceA,nonceB,nonceC], fn()
  eq nonceA, a
  eq nonceB, b
  eq nonceC, c

test "#713: destructuring assignment should return right-hand-side value", ->
  nonces = [nonceA={},nonceB={}]
  eq nonces, [a, b] = [c, d] = nonces
  eq nonceA, a
  eq nonceA, c
  eq nonceB, b
  eq nonceB, d

test "destructuring assignment with splats", ->
  a = {}; b = {}; c = {}; d = {}; e = {}
  [x,y...,z] = [a,b,c,d,e]
  eq a, x
  arrayEq [b,c,d], y
  eq e, z

test "deep destructuring assignment with splats", ->
  a={}; b={}; c={}; d={}; e={}; f={}; g={}; h={}; i={}
  [u, [v, w..., x], y..., z] = [a, [b, c, d, e], f, g, h, i]
  eq a, u
  eq b, v
  arrayEq [c,d], w
  eq e, x
  arrayEq [f,g,h], y
  eq i, z

test "destructuring assignment with objects", ->
  a={}; b={}; c={}
  obj = {a,b,c}
  {a:x, b:y, c:z} = obj
  eq a, x
  eq b, y
  eq c, z

test "deep destructuring assignment with objects", ->
  a={}; b={}; c={}; d={}
  obj = {
    a
    b: {
      'c': {
        d: [
          b
          {e: c, f: d}
        ]
      }
    }
  }
  {a: w, 'b': {c: d: [x, {'f': z, e: y}]}} = obj
  eq a, w
  eq b, x
  eq c, y
  eq d, z

test "destructuring assignment with objects and splats", ->
  a={}; b={}; c={}; d={}
  obj = a: b: [a, b, c, d]
  {a: b: [y, z...]} = obj
  eq a, y
  arrayEq [b,c,d], z

test "destructuring assignment against an expression", ->
  a={}; b={}
  [y, z] = if true then [a, b] else [b, a]
  eq a, y
  eq b, z

test "bracket insertion when necessary", ->
  [a] = [0] ? [1]
  eq a, 0

# for implicit destructuring assignment in comprehensions, see the comprehension tests

test "destructuring assignment with context (@) properties", ->
  a={}; b={}; c={}; d={}; e={}
  obj =
    fn: () ->
      local = [a, {b, c}, d, e]
      [@a, {b: @b, c: @c}, @d, @e] = local
  eq undefined, obj[key] for key in ['a','b','c','d','e']
  obj.fn()
  eq a, obj.a
  eq b, obj.b
  eq c, obj.c
  eq d, obj.d
  eq e, obj.e

test "#1024: destructure empty assignments to produce javascript-like results", ->
  eq 2 * [] = 3 + 5, 16

test "#1005: invalid identifiers allowed on LHS of destructuring assignment", ->
  disallowed = ['eval', 'arguments'].concat CoffeeScript.RESERVED
  throws (-> CoffeeScript.compile "[#{disallowed.join ', '}] = x"), null, 'all disallowed'
  throws (-> CoffeeScript.compile "[#{disallowed.join '..., '}...] = x"), null, 'all disallowed as splats'
  t = tSplat = null
  for v in disallowed when v isnt 'class' # `class` by itself is an expression
    throws (-> CoffeeScript.compile t), null, t = "[#{v}] = x"
    throws (-> CoffeeScript.compile tSplat), null, tSplat = "[#{v}...] = x"
  doesNotThrow ->
    for v in disallowed
      CoffeeScript.compile "[a.#{v}] = x"
      CoffeeScript.compile "[a.#{v}...] = x"
      CoffeeScript.compile "[@#{v}] = x"
      CoffeeScript.compile "[@#{v}...] = x"

test "#2055: destructuring assignment with `new`", ->
  {length} = new Array
  eq 0, length

test "#156: destructuring with expansion", ->
  array = [1..5]
  [first, ..., last] = array
  eq 1, first
  eq 5, last
  [..., lastButOne, last] = array
  eq 4, lastButOne
  eq 5, last
  [first, second, ..., last] = array
  eq 2, second
  [..., last] = 'strings as well -> x'
  eq 'x', last
  throws (-> CoffeeScript.compile "[1, ..., 3]"),        null, "prohibit expansion outside of assignment"
  throws (-> CoffeeScript.compile "[..., a, b...] = c"), null, "prohibit expansion and a splat"
  throws (-> CoffeeScript.compile "[...] = c"),          null, "prohibit lone expansion"

test "destructuring with dynamic keys", ->
  {"#{'a'}": a, """#{'b'}""": b, c} = {a: 1, b: 2, c: 3}
  eq 1, a
  eq 2, b
  eq 3, c
  throws -> CoffeeScript.compile '{"#{a}"} = b'

test "simple array destructuring defaults", ->
  [a = 1] = []
  eq 1, a
  [a = 2] = [undefined]
  eq 2, a
  [a = 3] = [null]
  eq 3, a
  [a = 4] = [0]
  eq 0, a
  arr = [a = 5]
  eq 5, a
  arrayEq [5], arr

test "simple object destructuring defaults", ->
  {b = 1} = {}
  eq b, 1
  {b = 2} = {b: undefined}
  eq b, 2
  {b = 3} = {b: null}
  eq b, 3
  {b = 4} = {b: 0}
  eq b, 0

  {b: c = 1} = {}
  eq c, 1
  {b: c = 2} = {b: undefined}
  eq c, 2
  {b: c = 3} = {b: null}
  eq c, 3
  {b: c = 4} = {b: 0}
  eq c, 0

test "multiple array destructuring defaults", ->
  [a = 1, b = 2, c] = [null, 12, 13]
  eq a, 1
  eq b, 12
  eq c, 13
  [a, b = 2, c = 3] = [null, 12, 13]
  eq a, null
  eq b, 12
  eq c, 13
  [a = 1, b, c = 3] = [11, 12]
  eq a, 11
  eq b, 12
  eq c, 3

test "multiple object destructuring defaults", ->
  {a = 1, b: bb = 2, 'c': c = 3, "#{0}": d = 4} = {"#{'b'}": 12}
  eq a, 1
  eq bb, 12
  eq c, 3
  eq d, 4

test "array destructuring defaults with splats", ->
  [..., a = 9] = []
  eq a, 9
  [..., b = 9] = [19]
  eq b, 19

test "deep destructuring assignment with defaults", ->
  [a, [{b = 1, c = 3}] = [c: 2]] = [0]
  eq a, 0
  eq b, 1
  eq c, 2

test "destructuring assignment with context (@) properties and defaults", ->
  a={}; b={}; c={}; d={}; e={}
  obj =
    fn: () ->
      local = [a, {b, c: null}, d]
      [@a, {b: @b = b, @c = c}, @d, @e = e] = local
  eq undefined, obj[key] for key in ['a','b','c','d','e']
  obj.fn()
  eq a, obj.a
  eq b, obj.b
  eq c, obj.c
  eq d, obj.d
  eq e, obj.e

test "destructuring assignment with defaults single evaluation", ->
  callCount = 0
  fn = -> callCount++
  [a = fn()] = []
  eq 0, a
  eq 1, callCount
  [a = fn()] = [10]
  eq 10, a
  eq 1, callCount
  {a = fn(), b: c = fn()} = {a: 20, b: null}
  eq 20, a
  eq c, 1
  eq callCount, 2


# Existential Assignment

test "existential assignment", ->
  nonce = {}
  a = false
  a ?= nonce
  eq false, a
  b = undefined
  b ?= nonce
  eq nonce, b
  c = null
  c ?= nonce
  eq nonce, c

test "#1627: prohibit conditional assignment of undefined variables", ->
  throws (-> CoffeeScript.compile "x ?= 10"),        null, "prohibit (x ?= 10)"
  throws (-> CoffeeScript.compile "x ||= 10"),       null, "prohibit (x ||= 10)"
  throws (-> CoffeeScript.compile "x or= 10"),       null, "prohibit (x or= 10)"
  throws (-> CoffeeScript.compile "do -> x ?= 10"),  null, "prohibit (do -> x ?= 10)"
  throws (-> CoffeeScript.compile "do -> x ||= 10"), null, "prohibit (do -> x ||= 10)"
  throws (-> CoffeeScript.compile "do -> x or= 10"), null, "prohibit (do -> x or= 10)"
  doesNotThrow (-> CoffeeScript.compile "x = null; x ?= 10"),        "allow (x = null; x ?= 10)"
  doesNotThrow (-> CoffeeScript.compile "x = null; x ||= 10"),       "allow (x = null; x ||= 10)"
  doesNotThrow (-> CoffeeScript.compile "x = null; x or= 10"),       "allow (x = null; x or= 10)"
  doesNotThrow (-> CoffeeScript.compile "x = null; do -> x ?= 10"),  "allow (x = null; do -> x ?= 10)"
  doesNotThrow (-> CoffeeScript.compile "x = null; do -> x ||= 10"), "allow (x = null; do -> x ||= 10)"
  doesNotThrow (-> CoffeeScript.compile "x = null; do -> x or= 10"), "allow (x = null; do -> x or= 10)"

  throws (-> CoffeeScript.compile "-> -> -> x ?= 10"), null, "prohibit (-> -> -> x ?= 10)"
  doesNotThrow (-> CoffeeScript.compile "x = null; -> -> -> x ?= 10"), "allow (x = null; -> -> -> x ?= 10)"

test "more existential assignment", ->
  global.temp ?= 0
  eq global.temp, 0
  global.temp or= 100
  eq global.temp, 100
  delete global.temp

test "#1348, #1216: existential assignment compilation", ->
  nonce = {}
  a = nonce
  b = (a ?= 0)
  eq nonce, b
  #the first ?= compiles into a statement; the second ?= compiles to a ternary expression
  eq a ?= b ?= 1, nonce

  if a then a ?= 2 else a = 3
  eq a, nonce

test "#1591, #1101: splatted expressions in destructuring assignment must be assignable", ->
  nonce = {}
  for nonref in ['', '""', '0', 'f()', '(->)'].concat CoffeeScript.RESERVED
    eq nonce, (try CoffeeScript.compile "[#{nonref}...] = v" catch e then nonce)

test "#1643: splatted accesses in destructuring assignments should not be declared as variables", ->
  nonce = {}
  accesses = ['o.a', 'o["a"]', '(o.a)', '(o.a).a', '@o.a', 'C::a', 'C::', 'f().a', 'o?.a', 'o?.a.b', 'f?().a']
  for access in accesses
    for i,j in [1,2,3] #position can matter
      code =
        """
        nonce = {}; nonce2 = {}; nonce3 = {};
        @o = o = new (class C then a:{}); f = -> o
        [#{new Array(i).join('x,')}#{access}...] = [#{new Array(i).join('0,')}nonce, nonce2, nonce3]
        unless #{access}[0] is nonce and #{access}[1] is nonce2 and #{access}[2] is nonce3 then throw new Error('[...]')
        """
      eq nonce, unless (try CoffeeScript.run code, bare: true catch e then true) then nonce
  # subpatterns like `[[a]...]` and `[{a}...]`
  subpatterns = ['[sub, sub2, sub3]', '{0: sub, 1: sub2, 2: sub3}']
  for subpattern in subpatterns
    for i,j in [1,2,3]
      code =
        """
        nonce = {}; nonce2 = {}; nonce3 = {};
        [#{new Array(i).join('x,')}#{subpattern}...] = [#{new Array(i).join('0,')}nonce, nonce2, nonce3]
        unless sub is nonce and sub2 is nonce2 and sub3 is nonce3 then throw new Error('[sub...]')
        """
      eq nonce, unless (try CoffeeScript.run code, bare: true catch e then true) then nonce

test "#1838: Regression with variable assignment", ->
  name =
  'dave'

  eq name, 'dave'

test '#2211: splats in destructured parameters', ->
  doesNotThrow -> CoffeeScript.compile '([a...]) ->'
  doesNotThrow -> CoffeeScript.compile '([a...],b) ->'
  doesNotThrow -> CoffeeScript.compile '([a...],[b...]) ->'
  throws -> CoffeeScript.compile '([a...,[a...]]) ->'
  doesNotThrow -> CoffeeScript.compile '([a...,[b...]]) ->'

test '#2213: invocations within destructured parameters', ->
  throws -> CoffeeScript.compile '([a()])->'
  throws -> CoffeeScript.compile '([a:b()])->'
  throws -> CoffeeScript.compile '([a:b.c()])->'
  throws -> CoffeeScript.compile '({a()})->'
  throws -> CoffeeScript.compile '({a:b()})->'
  throws -> CoffeeScript.compile '({a:b.c()})->'

test '#2532: compound assignment with terminator', ->
  doesNotThrow -> CoffeeScript.compile """
  a = "hello"
  a +=
  "
  world
  !
  "
  """

test "#2613: parens on LHS of destructuring", ->
  a = {}
  [(a).b] = [1, 2, 3]
  eq a.b, 1

test "#2181: conditional assignment as a subexpression", ->
  a = false
  false && a or= true
  eq false, a
  eq false, not a or= true

test "#1500: Assignment to variables similar to generated variables", ->
  len = 0
  x = ((results = null; n) for n in [1, 2, 3])
  arrayEq [1, 2, 3], x
  eq 0, len

  for x in [1, 2, 3]
    f = ->
      i = 0
    f()
    eq 'undefined', typeof i

  ref = 2
  x = ref * 2 ? 1
  eq x, 4
  eq 'undefined', typeof ref1

  x = {}
  base = -> x
  name = -1
  base()[-name] ?= 2
  eq x[1], 2
  eq base(), x
  eq name, -1

  f = (@a, a) -> [@a, a]
  arrayEq [1, 2], f.call scope = {}, 1, 2
  eq 1, scope.a

  try throw 'foo'
  catch error
    eq error, 'foo'

  eq error, 'foo'

  doesNotThrow -> CoffeeScript.compile '(@slice...) ->'

test "Assignment to variables similar to helper functions", ->
  f = (slice...) -> slice
  arrayEq [1, 2, 3], f 1, 2, 3
  eq 'undefined', typeof slice1

  class A
  class B extends A
    extend = 3
    hasProp = 4
    value: 5
    method: (bind, bind1) => [bind, bind1, extend, hasProp, @value]
  {method} = new B
  arrayEq [1, 2, 3, 4, 5], method 1, 2

  modulo = -1 %% 3
  eq 2, modulo

  indexOf = [1, 2, 3]
  ok 2 in indexOf

</script>
<script type="text/x-coffeescript" class="test" id="booleans">
# Boolean Literals
# ----------------

# TODO: add method invocation tests: true.toString() is "true"

test "#764 Booleans should be indexable", ->
  toString = Boolean::toString

  eq toString, true['toString']
  eq toString, false['toString']
  eq toString, yes['toString']
  eq toString, no['toString']
  eq toString, on['toString']
  eq toString, off['toString']

  eq toString, true.toString
  eq toString, false.toString
  eq toString, yes.toString
  eq toString, no.toString
  eq toString, on.toString
  eq toString, off.toString

</script>
<script type="text/x-coffeescript" class="test" id="classes">
# Classes
# -------

# * Class Definition
# * Class Instantiation
# * Inheritance and Super

test "classes with a four-level inheritance chain", ->

  class Base
    func: (string) ->
      "zero/#{string}"

    @static: (string) ->
      "static/#{string}"

  class FirstChild extends Base
    func: (string) ->
      super('one/') + string

  SecondChild = class extends FirstChild
    func: (string) ->
      super('two/') + string

  thirdCtor = ->
    @array = [1, 2, 3]

  class ThirdChild extends SecondChild
    constructor: -> thirdCtor.call this

    # Gratuitous comment for testing.
    func: (string) ->
      super('three/') + string

  result = (new ThirdChild).func 'four'

  ok result is 'zero/one/two/three/four'
  ok Base.static('word') is 'static/word'

  FirstChild::func = (string) ->
    super('one/').length + string

  result = (new ThirdChild).func 'four'

  ok result is '9two/three/four'

  ok (new ThirdChild).array.join(' ') is '1 2 3'


test "constructors with inheritance and super", ->

  identity = (f) -> f

  class TopClass
    constructor: (arg) ->
      @prop = 'top-' + arg

  class SuperClass extends TopClass
    constructor: (arg) ->
      identity super 'super-' + arg

  class SubClass extends SuperClass
    constructor: ->
      identity super 'sub'

  ok (new SubClass).prop is 'top-super-sub'


test "Overriding the static property new doesn't clobber Function::new", ->

  class OneClass
    @new: 'new'
    function: 'function'
    constructor: (name) -> @name = name

  class TwoClass extends OneClass
  delete TwoClass.new

  Function.prototype.new = -> new this arguments...

  ok (TwoClass.new('three')).name is 'three'
  ok (new OneClass).function is 'function'
  ok OneClass.new is 'new'

  delete Function.prototype.new


test "basic classes, again, but in the manual prototype style", ->

  Base = ->
  Base::func = (string) ->
    'zero/' + string
  Base::['func-func'] = (string) ->
    "dynamic-#{string}"

  FirstChild = ->
  SecondChild = ->
  ThirdChild = ->
    @array = [1, 2, 3]
    this

  ThirdChild extends SecondChild extends FirstChild extends Base

  FirstChild::func = (string) ->
    super('one/') + string

  SecondChild::func = (string) ->
    super('two/') + string

  ThirdChild::func = (string) ->
    super('three/') + string

  result = (new ThirdChild).func 'four'

  ok result is 'zero/one/two/three/four'

  ok (new ThirdChild)['func-func']('thing') is 'dynamic-thing'


test "super with plain ol' prototypes", ->

  TopClass = ->
  TopClass::func = (arg) ->
    'top-' + arg

  SuperClass = ->
  SuperClass extends TopClass
  SuperClass::func = (arg) ->
    super 'super-' + arg

  SubClass = ->
  SubClass extends SuperClass
  SubClass::func = ->
    super 'sub'

  eq (new SubClass).func(), 'top-super-sub'


test "'@' referring to the current instance, and not being coerced into a call", ->

  class ClassName
    amI: ->
      @ instanceof ClassName

  obj = new ClassName
  ok obj.amI()


test "super() calls in constructors of classes that are defined as object properties", ->

  class Hive
    constructor: (name) -> @name = name

  class Hive.Bee extends Hive
    constructor: (name) -> super

  maya = new Hive.Bee 'Maya'
  ok maya.name is 'Maya'


test "classes with JS-keyword properties", ->

  class Class
    class: 'class'
    name: -> @class

  instance = new Class
  ok instance.class is 'class'
  ok instance.name() is 'class'


test "Classes with methods that are pre-bound to the instance, or statically, to the class", ->

  class Dog
    constructor: (name) ->
      @name = name

    bark: =>
      "#{@name} woofs!"

    @static = =>
      new this('Dog')

  spark = new Dog('Spark')
  fido  = new Dog('Fido')
  fido.bark = spark.bark

  ok fido.bark() is 'Spark woofs!'

  obj = func: Dog.static

  ok obj.func().name is 'Dog'


test "a bound function in a bound function", ->

  class Mini
    num: 10
    generate: =>
      for i in [1..3]
        =>
          @num

  m = new Mini
  eq (func() for func in m.generate()).join(' '), '10 10 10'


test "contructor called with varargs", ->

  class Connection
    constructor: (one, two, three) ->
      [@one, @two, @three] = [one, two, three]

    out: ->
      "#{@one}-#{@two}-#{@three}"

  list = [3, 2, 1]
  conn = new Connection list...
  ok conn instanceof Connection
  ok conn.out() is '3-2-1'


test "calling super and passing along all arguments", ->

  class Parent
    method: (args...) -> @args = args

  class Child extends Parent
    method: -> super

  c = new Child
  c.method 1, 2, 3, 4
  ok c.args.join(' ') is '1 2 3 4'


test "classes wrapped in decorators", ->

  func = (klass) ->
    klass::prop = 'value'
    klass

  func class Test
    prop2: 'value2'

  ok (new Test).prop  is 'value'
  ok (new Test).prop2 is 'value2'


test "anonymous classes", ->

  obj =
    klass: class
      method: -> 'value'

  instance = new obj.klass
  ok instance.method() is 'value'


test "Implicit objects as static properties", ->

  class Static
    @static =
      one: 1
      two: 2

  ok Static.static.one is 1
  ok Static.static.two is 2


test "nothing classes", ->

  c = class
  ok c instanceof Function


test "classes with static-level implicit objects", ->

  class A
    @static = one: 1
    two: 2

  class B
    @static = one: 1,
    two: 2

  eq A.static.one, 1
  eq A.static.two, undefined
  eq (new A).two, 2

  eq B.static.one, 1
  eq B.static.two, 2
  eq (new B).two, undefined


test "classes with value'd constructors", ->

  counter = 0
  classMaker = ->
    inner = ++counter
    ->
      @value = inner

  class One
    constructor: classMaker()

  class Two
    constructor: classMaker()

  eq (new One).value, 1
  eq (new Two).value, 2
  eq (new One).value, 1
  eq (new Two).value, 2


test "executable class bodies", ->

  class A
    if true
      b: 'b'
    else
      c: 'c'

  a = new A

  eq a.b, 'b'
  eq a.c, undefined


test "#2502: parenthesizing inner object values", ->

  class A
    category:  (type: 'string')
    sections:  (type: 'number', default: 0)

  eq (new A).category.type, 'string'

  eq (new A).sections.default, 0


test "conditional prototype property assignment", ->
  debug = false

  class Person
    if debug
      age: -> 10
    else
      age: -> 20

  eq (new Person).age(), 20


test "mild metaprogramming", ->

  class Base
    @attr: (name) ->
      @::[name] = (val) ->
        if arguments.length > 0
          @["_#{name}"] = val
        else
          @["_#{name}"]

  class Robot extends Base
    @attr 'power'
    @attr 'speed'

  robby = new Robot

  ok robby.power() is undefined

  robby.power 11
  robby.speed Infinity

  eq robby.power(), 11
  eq robby.speed(), Infinity


test "namespaced classes do not reserve their function name in outside scope", ->

  one = {}
  two = {}

  class one.Klass
    @label = "one"

  class two.Klass
    @label = "two"

  eq typeof Klass, 'undefined'
  eq one.Klass.label, 'one'
  eq two.Klass.label, 'two'


test "nested classes", ->

  class Outer
    constructor: ->
      @label = 'outer'

    class @Inner
      constructor: ->
        @label = 'inner'

  eq (new Outer).label, 'outer'
  eq (new Outer.Inner).label, 'inner'


test "variables in constructor bodies are correctly scoped", ->

  class A
    x = 1
    constructor: ->
      x = 10
      y = 20
    y = 2
    captured: ->
      {x, y}

  a = new A
  eq a.captured().x, 10
  eq a.captured().y, 2


test "Issue #924: Static methods in nested classes", ->

  class A
    @B: class
      @c = -> 5

  eq A.B.c(), 5


test "`class extends this`", ->

  class A
    func: -> 'A'

  B = null
  makeClass = ->
    B = class extends this
      func: -> super + ' B'

  makeClass.call A

  eq (new B()).func(), 'A B'


test "ensure that constructors invoked with splats return a new object", ->

  args = [1, 2, 3]
  Type = (@args) ->
  type = new Type args

  ok type and type instanceof Type
  ok type.args and type.args instanceof Array
  ok v is args[i] for v, i in type.args

  Type1 = (@a, @b, @c) ->
  type1 = new Type1 args...

  ok type1 instanceof   Type1
  eq type1.constructor, Type1
  ok type1.a is args[0] and type1.b is args[1] and type1.c is args[2]

  # Ensure that constructors invoked with splats cache the function.
  called = 0
  get = -> if called++ then false else class Type
  new get() args...

test "`new` shouldn't add extra parens", ->

  ok new Date().constructor is Date


test "`new` works against bare function", ->

  eq Date, new ->
    eq this, new => this
    Date


test "#1182: a subclass should be able to set its constructor to an external function", ->
  ctor = ->
    @val = 1
  class A
  class B extends A
    constructor: ctor
  eq (new B).val, 1

test "#1182: external constructors continued", ->
  ctor = ->
  class A
  class B extends A
    method: ->
    constructor: ctor
  ok B::method

test "#1313: misplaced __extends", ->
  nonce = {}
  class A
  class B extends A
    prop: nonce
    constructor: ->
  eq nonce, B::prop

test "#1182: execution order needs to be considered as well", ->
  counter = 0
  makeFn = (n) -> eq n, ++counter; ->
  class B extends (makeFn 1)
    @B: makeFn 2
    constructor: makeFn 3

test "#1182: external constructors with bound functions", ->
  fn = ->
    {one: 1}
    this
  class B
  class A
    constructor: fn
    method: => this instanceof A
  ok (new A).method.call(new B)

test "#1372: bound class methods with reserved names", ->
  class C
    delete: =>
  ok C::delete

test "#1380: `super` with reserved names", ->
  class C
    do: -> super
  ok C::do

  class B
    0: -> super
  ok B::[0]

test "#1464: bound class methods should keep context", ->
  nonce  = {}
  nonce2 = {}
  class C
    constructor: (@id) ->
    @boundStaticColon: => new this(nonce)
    @boundStaticEqual= => new this(nonce2)
  eq nonce,  C.boundStaticColon().id
  eq nonce2, C.boundStaticEqual().id

test "#1009: classes with reserved words as determined names", -> (->
  eq 'function', typeof (class @for)
  ok not /\beval\b/.test (class @eval).toString()
  ok not /\barguments\b/.test (class @arguments).toString()
).call {}

test "#1482: classes can extend expressions", ->
  id = (x) -> x
  nonce = {}
  class A then nonce: nonce
  class B extends id A
  eq nonce, (new B).nonce

test "#1598: super works for static methods too", ->

  class Parent
    method: ->
      'NO'
    @method: ->
      'yes'

  class Child extends Parent
    @method: ->
      'pass? ' + super

  eq Child.method(), 'pass? yes'

test "#1842: Regression with bound functions within bound class methods", ->

  class Store
    @bound: =>
      do =>
        eq this, Store

  Store.bound()

  # And a fancier case:

  class Store

    eq this, Store

    @bound: =>
      do =>
        eq this, Store

    @unbound: ->
      eq this, Store

    instance: =>
      ok this instanceof Store

  Store.bound()
  Store.unbound()
  (new Store).instance()

test "#1876: Class @A extends A", ->
  class A
  class @A extends A

  ok (new @A) instanceof A

test "#1813: Passing class definitions as expressions", ->
  ident = (x) -> x

  result = ident class A then x = 1

  eq result, A

  result = ident class B extends A
    x = 1

  eq result, B

test "#1966: external constructors should produce their return value", ->
  ctor = -> {}
  class A then constructor: ctor
  ok (new A) not instanceof A

test "#1980: regression with an inherited class with static function members", ->

  class A

  class B extends A
    @static: => 'value'

  eq B.static(), 'value'

test "#1534: class then 'use strict'", ->
  # [14.1 Directive Prologues and the Use Strict Directive](http://es5.github.com/#x14.1)
  nonce = {}
  error = 'do -> ok this'
  strictTest = "do ->'use strict';#{error}"
  return unless (try CoffeeScript.run strictTest, bare: yes catch e then nonce) is nonce

  throws -> CoffeeScript.run "class then 'use strict';#{error}", bare: yes
  doesNotThrow -> CoffeeScript.run "class then #{error}", bare: yes
  doesNotThrow -> CoffeeScript.run "class then #{error};'use strict'", bare: yes

  # comments are ignored in the Directive Prologue
  comments = ["""
  class
    ### comment ###
    'use strict'
    #{error}""",
  """
  class
    ### comment 1 ###
    ### comment 2 ###
    'use strict'
    #{error}""",
  """
  class
    ### comment 1 ###
    ### comment 2 ###
    'use strict'
    #{error}
    ### comment 3 ###"""
  ]
  throws (-> CoffeeScript.run comment, bare: yes) for comment in comments

  # [ES5 §14.1](http://es5.github.com/#x14.1) allows for other directives
  directives = ["""
  class
    'directive 1'
    'use strict'
    #{error}""",
  """
  class
    'use strict'
    'directive 2'
    #{error}""",
  """
  class
    ### comment 1 ###
    'directive 1'
    'use strict'
    #{error}""",
  """
  class
    ### comment 1 ###
    'directive 1'
    ### comment 2 ###
    'use strict'
    #{error}"""
  ]
  throws (-> CoffeeScript.run directive, bare: yes) for directive in directives

test "#2052: classes should work in strict mode", ->
  try
    do ->
      'use strict'
      class A
  catch e
    ok no

test "directives in class with extends ", ->
  strictTest = """
    class extends Object
      ### comment ###
      'use strict'
      do -> eq this, undefined
  """
  CoffeeScript.run strictTest, bare: yes

test "#2630: class bodies can't reference arguments", ->
  throws ->
    CoffeeScript.compile('class Test then arguments')

  # #4320: Don't be too eager when checking, though.
  class Test
    arguments: 5
  eq 5, Test::arguments

test "#2319: fn class n extends o.p [INDENT] x = 123", ->
  first = ->

  base = onebase: ->

  first class OneKeeper extends base.onebase
    one = 1
    one: -> one

  eq new OneKeeper().one(), 1


test "#2599: other typed constructors should be inherited", ->
  class Base
    constructor: -> return {}

  class Derived extends Base

  ok (new Derived) not instanceof Derived
  ok (new Derived) not instanceof Base
  ok (new Base) not instanceof Base

test "#2359: extending native objects that use other typed constructors requires defining a constructor", ->
  class BrokenArray extends Array
    method: -> 'no one will call me'

  brokenArray = new BrokenArray
  ok brokenArray not instanceof BrokenArray
  ok typeof brokenArray.method is 'undefined'

  class WorkingArray extends Array
    constructor: -> super
    method: -> 'yes!'

  workingArray = new WorkingArray
  ok workingArray instanceof WorkingArray
  eq 'yes!', workingArray.method()


test "#2782: non-alphanumeric-named bound functions", ->
  class A
    'b:c': =>
      'd'

  eq (new A)['b:c'](), 'd'


test "#2781: overriding bound functions", ->
  class A
    a: ->
        @b()
    b: =>
        1

  class B extends A
    b: =>
        2

  b = (new A).b
  eq b(), 1

  b = (new B).b
  eq b(), 2


test "#2791: bound function with destructured argument", ->
  class Foo
    method: ({a}) => 'Bar'

  eq (new Foo).method({a: 'Bar'}), 'Bar'


test "#2796: ditto, ditto, ditto", ->
  answer = null

  outsideMethod = (func) ->
    func.call message: 'wrong!'

  class Base
    constructor: ->
      @message = 'right!'
      outsideMethod @echo

    echo: =>
      answer = @message

  new Base
  eq answer, 'right!'

test "#3063: Class bodies cannot contain pure statements", ->
  throws -> CoffeeScript.compile """
    class extends S
      return if S.f
      @f: => this
  """

test "#2949: super in static method with reserved name", ->
  class Foo
    @static: -> 'baz'

  class Bar extends Foo
    @static: -> super

  eq Bar.static(), 'baz'

test "#3232: super in static methods (not object-assigned)", ->
  class Foo
    @baz = -> true
    @qux = -> true

  class Bar extends Foo
    @baz = -> super
    Bar.qux = -> super

  ok Bar.baz()
  ok Bar.qux()

test "#1392 calling `super` in methods defined on namespaced classes", ->
  class Base
    m: -> 5
    n: -> 4
  namespace =
    A: ->
    B: ->
  namespace.A extends Base

  namespace.A::m = -> super
  eq 5, (new namespace.A).m()
  namespace.B::m = namespace.A::m
  namespace.A::m = null
  eq 5, (new namespace.B).m()

  count = 0
  getNamespace = -> count++; namespace
  getNamespace().A::n = -> super
  eq 4, (new namespace.A).n()
  eq 1, count

  class C
    @a: ->
    @a extends Base
    @a::m = -> super
  eq 5, (new C.a).m()

test "dynamic method names and super", ->
  class Base
    @m: -> 6
    m: -> 5
    m2: -> 4.5
    n: -> 4
  A = ->
  A extends Base

  m = 'm'
  A::[m] = -> super
  m = 'n'
  eq 5, (new A).m()

  name = -> count++; 'n'

  count = 0
  A::[name()] = -> super
  eq 4, (new A).n()
  eq 1, count

  m = 'm'
  m2 = 'm2'
  count = 0
  class B extends Base
    @[name()] = -> super
    @::[m] = -> super
    "#{m2}": -> super
  b = new B
  m = m2 = 'n'
  eq 6, B.m()
  eq 5, b.m()
  eq 4.5, b.m2()
  eq 1, count

  class C extends B
    m: -> super
  eq 5, (new C).m()

</script>
<script type="text/x-coffeescript" class="test" id="cluster">
# Cluster Module
# ---------

return if testingBrowser?

cluster = require 'cluster'

if cluster.isMaster
  test "#2737 - cluster module can spawn workers from a coffeescript process", ->
    cluster.once 'exit', (worker, code) ->
      eq code, 0

    cluster.fork()
else
  process.exit 0

</script>
<script type="text/x-coffeescript" class="test" id="comments">
# Comments
# --------

# * Single-Line Comments
# * Block Comments

# Note: awkward spacing seen in some tests is likely intentional.

test "comments in objects", ->
  obj1 = {
  # comment
    # comment
      # comment
    one: 1
  # comment
    two: 2
      # comment
  }

  ok Object::hasOwnProperty.call(obj1,'one')
  eq obj1.one, 1
  ok Object::hasOwnProperty.call(obj1,'two')
  eq obj1.two, 2

test "comments in YAML-style objects", ->
  obj2 =
  # comment
    # comment
      # comment
    three: 3
  # comment
    four: 4
      # comment

  ok Object::hasOwnProperty.call(obj2,'three')
  eq obj2.three, 3
  ok Object::hasOwnProperty.call(obj2,'four')
  eq obj2.four, 4

test "comments following operators that continue lines", ->
  sum =
    1 +
    1 + # comment
    1
  eq 3, sum

test "comments in functions", ->
  fn = ->
  # comment
    false
    false   # comment
    false
    # comment

  # comment
    true

  ok fn()

  fn2 = -> #comment
    fn()
    # comment

  ok fn2()

test "trailing comment before an outdent", ->
  nonce = {}
  fn3 = ->
    if true
      undefined # comment
    nonce

  eq nonce, fn3()

test "comments in a switch", ->
  nonce = {}
  result = switch nonce #comment
    # comment
    when false then undefined
    # comment
    when null #comment
      undefined
    else nonce # comment

  eq nonce, result

test "comment with conditional statements", ->
  nonce = {}
  result = if false # comment
    undefined
  #comment
  else # comment
    nonce
    # comment
  eq nonce, result

test "spaced comments with conditional statements", ->
  nonce = {}
  result = if false
    undefined

  # comment
  else if false
    undefined

  # comment
  else
    nonce

  eq nonce, result


# Block Comments

###
  This is a here-comment.
  Kind of like a heredoc.
###

test "block comments in objects", ->
  a = {}
  b = {}
  obj = {
    a: a
    ###
    comment
    ###
    b: b
  }

  eq a, obj.a
  eq b, obj.b

test "block comments in YAML-style", ->
  a = {}
  b = {}
  obj =
    a: a
    ###
    comment
    ###
    b: b

  eq a, obj.a
  eq b, obj.b


test "block comments in functions", ->
  nonce = {}

  fn1 = ->
    true
    ###
    false
    ###

  ok fn1()

  fn2 =  ->
    ###
    block comment
    ###
    nonce

  eq nonce, fn2()

  fn3 = ->
    nonce
  ###
  block comment
  ###

  eq nonce, fn3()

  fn4 = ->
    one = ->
      ###
        block comment
      ###
      two = ->
        three = ->
          nonce

  eq nonce, fn4()()()()

test "block comments inside class bodies", ->
  class A
    a: ->

    ###
    Comment
    ###
    b: ->

  ok A.prototype.b instanceof Function

  class B
    ###
    Comment
    ###
    a: ->
    b: ->

  ok B.prototype.a instanceof Function

test "#2037: herecomments shouldn't imply line terminators", ->
  do (-> ### ###; fail)

test "#2916: block comment before implicit call with implicit object", ->
  fn = (obj) -> ok obj.a
  ### ###
  fn
    a: yes

test "#3132: Format single-line block comment nicely", ->
  input = """
  ### Single-line block comment without additional space here => ###"""

  result = """

  /* Single-line block comment without additional space here => */


  """
  eq CoffeeScript.compile(input, bare: on), result

test "#3132: Format multi-line block comment nicely", ->
  input = """
  ###
  # Multi-line
  # block
  # comment
  ###"""

  result = """

  /*
   * Multi-line
   * block
   * comment
   */


  """
  eq CoffeeScript.compile(input, bare: on), result

test "#3132: Format simple block comment nicely", ->
  input = """
  ###
  No
  Preceding hash
  ###"""

  result = """

  /*
  No
  Preceding hash
   */


  """

  eq CoffeeScript.compile(input, bare: on), result

test "#3132: Format indented block-comment nicely", ->
  input = """
  fn = () ->
    ###
    # Indented
    Multiline
    ###
    1"""

  result = """
  var fn;

  fn = function() {

    /*
     * Indented
    Multiline
     */
    return 1;
  };

  """
  eq CoffeeScript.compile(input, bare: on), result

# Although adequately working, block comment-placement is not yet perfect.
# (Considering a case where multiple variables have been declared …)
test "#3132: Format jsdoc-style block-comment nicely", ->
  input = """
  ###*
  # Multiline for jsdoc-"@doctags"
  #
  # @type {Function}
  ###
  fn = () -> 1
  """

  result = """

  /**
   * Multiline for jsdoc-"@doctags"
   *
   * @type {Function}
   */
  var fn;

  fn = function() {
    return 1;
  };

  """
  eq CoffeeScript.compile(input, bare: on), result

# Although adequately working, block comment-placement is not yet perfect.
# (Considering a case where multiple variables have been declared …)
test "#3132: Format hand-made (raw) jsdoc-style block-comment nicely", ->
  input = """
  ###*
   * Multiline for jsdoc-"@doctags"
   *
   * @type {Function}
  ###
  fn = () -> 1
  """

  result = """

  /**
   * Multiline for jsdoc-"@doctags"
   *
   * @type {Function}
   */
  var fn;

  fn = function() {
    return 1;
  };

  """
  eq CoffeeScript.compile(input, bare: on), result

# Although adequately working, block comment-placement is not yet perfect.
# (Considering a case where multiple variables have been declared …)
test "#3132: Place block-comments nicely", ->
  input = """
  ###*
  # A dummy class definition
  #
  # @class
  ###
  class DummyClass

    ###*
    # @constructor
    ###
    constructor: ->

    ###*
    # Singleton reference
    #
    # @type {DummyClass}
    ###
    @instance = new DummyClass()

  """

  result = """

  /**
   * A dummy class definition
   *
   * @class
   */
  var DummyClass;

  DummyClass = (function() {

    /**
     * @constructor
     */
    function DummyClass() {}


    /**
     * Singleton reference
     *
     * @type {DummyClass}
     */

    DummyClass.instance = new DummyClass();

    return DummyClass;

  })();

  """
  eq CoffeeScript.compile(input, bare: on), result

test "#3638: Demand a whitespace after # symbol", ->
  input = """
  ###
  #No
  #whitespace
  ###"""

  result = """

  /*
  #No
  #whitespace
   */


  """

  eq CoffeeScript.compile(input, bare: on), result

test "#3761: Multiline comment at end of an object", ->
  anObject =
    x: 3
    ###
    #Comment
    ###

  ok anObject.x is 3

test "#4375: UTF-8 characters in comments", ->
  # 智に働けば角が立つ、情に掉させば流される。
  ok yes

</script>
<script type="text/x-coffeescript" class="test" id="compilation">
# Compilation
# -----------

# helper to assert that a string should fail compilation
cantCompile = (code) ->
  throws -> CoffeeScript.compile code


test "ensure that carriage returns don't break compilation on Windows", ->
  doesNotThrow -> CoffeeScript.compile 'one\r\ntwo', bare: on

test "#3089 - don't mutate passed in options to compile", ->
  opts = {}
  CoffeeScript.compile '1 + 1', opts
  ok !opts.scope

test "--bare", ->
  eq -1, CoffeeScript.compile('x = y', bare: on).indexOf 'function'
  ok 'passed' is CoffeeScript.eval '"passed"', bare: on, filename: 'test'

test "header (#1778)", ->
  header = "// Generated by CoffeeScript #{CoffeeScript.VERSION}\n"
  eq 0, CoffeeScript.compile('x = y', header: on).indexOf header

test "header is disabled by default", ->
  header = "// Generated by CoffeeScript #{CoffeeScript.VERSION}\n"
  eq -1, CoffeeScript.compile('x = y').indexOf header

test "multiple generated references", ->
  a = {b: []}
  a.b[true] = -> this == a.b
  c = 0
  d = []
  ok a.b[0<++c<2] d...

test "splat on a line by itself is invalid", ->
  cantCompile "x 'a'\n...\n"

test "Issue 750", ->

  cantCompile 'f(->'

  cantCompile 'a = (break)'

  cantCompile 'a = (return 5 for item in list)'

  cantCompile 'a = (return 5 while condition)'

  cantCompile 'a = for x in y\n  return 5'

test "Issue #986: Unicode identifiers", ->
  λ = 5
  eq λ, 5

test "#2516: Unicode spaces should not be part of identifiers", ->
  a = (x) -> x * 2
  b = 3
  eq 6, a b # U+00A0 NO-BREAK SPACE
  eq 6, a b # U+1680 OGHAM SPACE MARK
  eq 6, a b # U+2000 EN QUAD
  eq 6, a b # U+2001 EM QUAD
  eq 6, a b # U+2002 EN SPACE
  eq 6, a b # U+2003 EM SPACE
  eq 6, a b # U+2004 THREE-PER-EM SPACE
  eq 6, a b # U+2005 FOUR-PER-EM SPACE
  eq 6, a b # U+2006 SIX-PER-EM SPACE
  eq 6, a b # U+2007 FIGURE SPACE
  eq 6, a b # U+2008 PUNCTUATION SPACE
  eq 6, a b # U+2009 THIN SPACE
  eq 6, a b # U+200A HAIR SPACE
  eq 6, a b # U+202F NARROW NO-BREAK SPACE
  eq 6, a b # U+205F MEDIUM MATHEMATICAL SPACE
  eq 6, a　b # U+3000 IDEOGRAPHIC SPACE

  # #3560: Non-breaking space (U+00A0) (before `'c'`)
  eq 5, {c: 5}[ 'c' ]

  # A line where every space in non-breaking
  eq 1 + 1, 2  

test "don't accidentally stringify keywords", ->
  ok (-> this == 'this')() is false

test "#1026: no if/else/else allowed", ->
  cantCompile '''
    if a
      b
    else
      c
    else
      d
  '''

test "#1050: no closing asterisk comments from within block comments", ->
  cantCompile "### */ ###"

test "#1273: escaping quotes at the end of heredocs", ->
  cantCompile '"""\\"""' # """\"""
  cantCompile '"""\\\\\\"""' # """\\\"""

test "#1106: __proto__ compilation", ->
  object = eq
  @["__proto__"] = true
  ok __proto__

test "reference named hasOwnProperty", ->
  CoffeeScript.compile 'hasOwnProperty = 0; a = 1'

test "#1055: invalid keys in real (but not work-product) objects", ->
  cantCompile "@key: value"

test "#1066: interpolated strings are not implicit functions", ->
  cantCompile '"int#{er}polated" arg'

test "#2846: while with empty body", ->
  CoffeeScript.compile 'while 1 then', {sourceMap: true}

test "#2944: implicit call with a regex argument", ->
  CoffeeScript.compile 'o[key] /regex/'

test "#3001: `own` shouldn't be allowed in a `for`-`in` loop", ->
  cantCompile "a for own b in c"

test "#2994: single-line `if` requires `then`", ->
  cantCompile "if b else x"

</script>
<script type="text/x-coffeescript" class="test" id="comprehensions">
# Comprehensions
# --------------

# * Array Comprehensions
# * Range Comprehensions
# * Object Comprehensions
# * Implicit Destructuring Assignment
# * Comprehensions with Nonstandard Step

# TODO: refactor comprehension tests

test "Basic array comprehensions.", ->

  nums    = (n * n for n in [1, 2, 3] when n & 1)
  results = (n * 2 for n in nums)

  ok results.join(',') is '2,18'


test "Basic object comprehensions.", ->

  obj   = {one: 1, two: 2, three: 3}
  names = (prop + '!' for prop of obj)
  odds  = (prop + '!' for prop, value of obj when value & 1)

  ok names.join(' ') is "one! two! three!"
  ok odds.join(' ')  is "one! three!"


test "Basic range comprehensions.", ->

  nums = (i * 3 for i in [1..3])

  negs = (x for x in [-20..-5*2])
  negs = negs[0..2]

  result = nums.concat(negs).join(', ')

  ok result is '3, 6, 9, -20, -19, -18'


test "With range comprehensions, you can loop in steps.", ->

  results = (x for x in [0...15] by 5)
  ok results.join(' ') is '0 5 10'

  results = (x for x in [0..100] by 10)
  ok results.join(' ') is '0 10 20 30 40 50 60 70 80 90 100'


test "And can loop downwards, with a negative step.", ->

  results = (x for x in [5..1])

  ok results.join(' ') is '5 4 3 2 1'
  ok results.join(' ') is [(10-5)..(-2+3)].join(' ')

  results = (x for x in [10..1])
  ok results.join(' ') is [10..1].join(' ')

  results = (x for x in [10...0] by -2)
  ok results.join(' ') is [10, 8, 6, 4, 2].join(' ')


test "Range comprehension gymnastics.", ->

  eq "#{i for i in [5..1]}", '5,4,3,2,1'
  eq "#{i for i in [5..-5] by -5}", '5,0,-5'

  a = 6
  b = 0
  c = -2

  eq "#{i for i in [a..b]}", '6,5,4,3,2,1,0'
  eq "#{i for i in [a..b] by c}", '6,4,2,0'


test "Multiline array comprehension with filter.", ->

  evens = for num in [1, 2, 3, 4, 5, 6] when not (num & 1)
             num *= -1
             num -= 2
             num * -1
  eq evens + '', '4,6,8'


  test "The in operator still works, standalone.", ->

    ok 2 of evens


test "all isn't reserved.", ->

  all = 1


test "Ensure that the closure wrapper preserves local variables.", ->

  obj = {}

  for method in ['one', 'two', 'three'] then do (method) ->
    obj[method] = ->
      "I'm " + method

  ok obj.one()   is "I'm one"
  ok obj.two()   is "I'm two"
  ok obj.three() is "I'm three"


test "Index values at the end of a loop.", ->

  i = 0
  for i in [1..3]
    -> 'func'
    break if false
  ok i is 4


test "Ensure that local variables are closed over for range comprehensions.", ->

  funcs = for i in [1..3]
    do (i) ->
      -> -i

  eq (func() for func in funcs).join(' '), '-1 -2 -3'
  ok i is 4


test "Even when referenced in the filter.", ->

  list = ['one', 'two', 'three']

  methods = for num, i in list when num isnt 'two' and i isnt 1
    do (num, i) ->
      -> num + ' ' + i

  ok methods.length is 2
  ok methods[0]() is 'one 0'
  ok methods[1]() is 'three 2'


test "Even a convoluted one.", ->

  funcs = []

  for i in [1..3]
    do (i) ->
      x = i * 2
      ((z)->
        funcs.push -> z + ' ' + i
      )(x)

  ok (func() for func in funcs).join(', ') is '2 1, 4 2, 6 3'

  funcs = []

  results = for i in [1..3]
    do (i) ->
      z = (x * 3 for x in [1..i])
      ((a, b, c) -> [a, b, c].join(' ')).apply this, z

  ok results.join(', ') is '3  , 3 6 , 3 6 9'


test "Naked ranges are expanded into arrays.", ->

  array = [0..10]
  ok(num % 2 is 0 for num in array by 2)


test "Nested shared scopes.", ->

  foo = ->
    for i in [0..7]
      do (i) ->
        for j in [0..7]
          do (j) ->
            -> i + j

  eq foo()[3][4](), 7


test "Scoped loop pattern matching.", ->

  a = [[0], [1]]
  funcs = []

  for [v] in a
    do (v) ->
      funcs.push -> v

  eq funcs[0](), 0
  eq funcs[1](), 1


test "Nested comprehensions.", ->

  multiLiner =
    for x in [3..5]
      for y in [3..5]
        [x, y]

  singleLiner =
    (([x, y] for y in [3..5]) for x in [3..5])

  ok multiLiner.length is singleLiner.length
  ok 5 is multiLiner[2][2][1]
  ok 5 is singleLiner[2][2][1]


test "Comprehensions within parentheses.", ->

  result = null
  store = (obj) -> result = obj
  store (x * 2 for x in [3, 2, 1])

  ok result.join(' ') is '6 4 2'


test "Closure-wrapped comprehensions that refer to the 'arguments' object.", ->

  expr = ->
    result = (item * item for item in arguments)

  ok expr(2, 4, 8).join(' ') is '4 16 64'


test "Fast object comprehensions over all properties, including prototypal ones.", ->

  class Cat
    constructor: -> @name = 'Whiskers'
    breed: 'tabby'
    hair:  'cream'

  whiskers = new Cat
  own = (value for own key, value of whiskers)
  all = (value for key, value of whiskers)

  ok own.join(' ') is 'Whiskers'
  ok all.sort().join(' ') is 'Whiskers cream tabby'


test "Optimized range comprehensions.", ->

  exxes = ('x' for [0...10])
  ok exxes.join(' ') is 'x x x x x x x x x x'


test "#3671: Allow step in optimized range comprehensions.", ->

  exxes = ('x' for [0...10] by 2)
  eq exxes.join(' ') , 'x x x x x'


test "#3671: Disallow guard in optimized range comprehensions.", ->

  throws -> CoffeeScript.compile "exxes = ('x' for [0...10] when a)"


test "Loop variables should be able to reference outer variables", ->
  outer = 1
  do ->
    null for outer in [1, 2, 3]
  eq outer, 3


test "Lenient on pure statements not trying to reach out of the closure", ->

  val = for i in [1]
    for j in [] then break
    i
  ok val[0] is i


test "Comprehensions only wrap their last line in a closure, allowing other lines
  to have pure expressions in them.", ->

  func = -> for i in [1]
    break if i is 2
    j for j in [1]

  ok func()[0][0] is 1

  i = 6
  odds = while i--
    continue unless i & 1
    i

  ok odds.join(', ') is '5, 3, 1'


test "Issue #897: Ensure that plucked function variables aren't leaked.", ->

  facets = {}
  list = ['one', 'two']

  (->
    for entity in list
      facets[entity] = -> entity
  )()

  eq typeof entity, 'undefined'
  eq facets['two'](), 'two'


test "Issue #905. Soaks as the for loop subject.", ->

  a = {b: {c: [1, 2, 3]}}
  for d in a.b?.c
    e = d

  eq e, 3


test "Issue #948. Capturing loop variables.", ->

  funcs = []
  list  = ->
    [1, 2, 3]

  for y in list()
    do (y) ->
      z = y
      funcs.push -> "y is #{y} and z is #{z}"

  eq funcs[1](), "y is 2 and z is 2"


test "Cancel the comprehension if there's a jump inside the loop.", ->

  result = try
    for i in [0...10]
      continue if i < 5
    i

  eq result, 10


test "Comprehensions over break.", ->

  arrayEq (break for [1..10]), []


test "Comprehensions over continue.", ->

  arrayEq (continue for [1..10]), []


test "Comprehensions over function literals.", ->

  a = 0
  for f in [-> a = 1]
    do (f) ->
      do f

  eq a, 1


test "Comprehensions that mention arguments.", ->

  list = [arguments: 10]
  args = for f in list
    do (f) ->
      f.arguments
  eq args[0], 10


test "expression conversion under explicit returns", ->
  nonce = {}
  fn = ->
    return (nonce for x in [1,2,3])
  arrayEq [nonce,nonce,nonce], fn()
  fn = ->
    return [nonce for x in [1,2,3]][0]
  arrayEq [nonce,nonce,nonce], fn()
  fn = ->
    return [(nonce for x in [1..3])][0]
  arrayEq [nonce,nonce,nonce], fn()


test "implicit destructuring assignment in object of objects", ->
  a={}; b={}; c={}
  obj = {
    a: { d: a },
    b: { d: b }
    c: { d: c }
  }
  result = ([y,z] for y, { d: z } of obj)
  arrayEq [['a',a],['b',b],['c',c]], result


test "implicit destructuring assignment in array of objects", ->
  a={}; b={}; c={}; d={}; e={}; f={}
  arr = [
    { a: a, b: { c: b } },
    { a: c, b: { c: d } },
    { a: e, b: { c: f } }
  ]
  result = ([y,z] for { a: y, b: { c: z } } in arr)
  arrayEq [[a,b],[c,d],[e,f]], result


test "implicit destructuring assignment in array of arrays", ->
  a={}; b={}; c={}; d={}; e={}; f={}
  arr = [[a, [b]], [c, [d]], [e, [f]]]
  result = ([y,z] for [y, [z]] in arr)
  arrayEq [[a,b],[c,d],[e,f]], result

test "issue #1124: don't assign a variable in two scopes", ->
  lista = [1, 2, 3, 4, 5]
  listb = (_i + 1 for _i in lista)
  arrayEq [2, 3, 4, 5, 6], listb

test "#1326: `by` value is uncached", ->
  a = [0,1,2]
  fi = gi = hi = 0
  f = -> ++fi
  g = -> ++gi
  h = -> ++hi

  forCompile = []
  rangeCompileSimple = []

  #exercises For.compile
  for v, i in a by f()
    forCompile.push i

  #exercises Range.compileSimple
  rangeCompileSimple = (i for i in [0..2] by g())

  arrayEq a, forCompile
  arrayEq a, rangeCompileSimple
  #exercises Range.compile
  eq "#{i for i in [0..2] by h()}", '0,1,2'

test "#1669: break/continue should skip the result only for that branch", ->
  ns = for n in [0..99]
    if n > 9
      break
    else if n & 1
      continue
    else
      n
  eq "#{ns}", '0,2,4,6,8'

  # `else undefined` is implied.
  ns = for n in [1..9]
    if n % 2
      continue unless n % 5
      n
  eq "#{ns}", "1,,3,,,7,,9"

  # Ditto.
  ns = for n in [1..9]
    switch
      when n % 2
        continue unless n % 5
        n
  eq "#{ns}", "1,,3,,,7,,9"

test "#1850: inner `for` should not be expression-ized if `return`ing", ->
  eq '3,4,5', do ->
    for a in [1..9] then \
    for b in [1..9]
      c = Math.sqrt a*a + b*b
      return String [a, b, c] unless c % 1

test "#1910: loop index should be mutable within a loop iteration and immutable between loop iterations", ->
  n = 1
  iterations = 0
  arr = [0..n]
  for v, k in arr
    ++iterations
    v = k = 5
    eq 5, k
  eq 2, k
  eq 2, iterations

  iterations = 0
  for v in [0..n]
    ++iterations
  eq 2, k
  eq 2, iterations

  arr = ([v, v + 1] for v in [0..5])
  iterations = 0
  for [v0, v1], k in arr when v0
    k += 3
    ++iterations
  eq 6, k
  eq 5, iterations

test "#2007: Return object literal from comprehension", ->
  y = for x in [1, 2]
    foo: "foo" + x
  eq 2, y.length
  eq "foo1", y[0].foo
  eq "foo2", y[1].foo

  x = 2
  y = while x
    x: --x
  eq 2, y.length
  eq 1, y[0].x
  eq 0, y[1].x

test "#2274: Allow @values as loop variables", ->
  obj = {
    item: null
    method: ->
      for @item in [1, 2, 3]
        null
  }
  eq obj.item, null
  obj.method()
  eq obj.item, 3

test "#4411: Allow @values as loop indices", ->
  obj =
    index: null
    get: -> @index
    method: ->
      @get() for _, @index in [1, 2, 3]
  eq obj.index, null
  arrayEq obj.method(), [0, 1, 2]
  eq obj.index, 3

test "#2525, #1187, #1208, #1758, looping over an array forwards", ->
  list = [0, 1, 2, 3, 4]

  ident = (x) -> x

  arrayEq (i for i in list), list

  arrayEq (index for i, index in list), list

  arrayEq (i for i in list by 1), list

  arrayEq (i for i in list by ident 1), list

  arrayEq (i for i in list by ident(1) * 2), [0, 2, 4]

  arrayEq (index for i, index in list by ident(1) * 2), [0, 2, 4]

test "#2525, #1187, #1208, #1758, looping over an array backwards", ->
  list = [0, 1, 2, 3, 4]
  backwards = [4, 3, 2, 1, 0]

  ident = (x) -> x

  arrayEq (i for i in list by -1), backwards

  arrayEq (index for i, index in list by -1), backwards

  arrayEq (i for i in list by ident -1), backwards

  arrayEq (i for i in list by ident(-1) * 2), [4, 2, 0]

  arrayEq (index for i, index in list by ident(-1) * 2), [4, 2, 0]

test "splats in destructuring in comprehensions", ->
  list = [[0, 1, 2], [2, 3, 4], [4, 5, 6]]
  arrayEq (seq for [rep, seq...] in list), [[1, 2], [3, 4], [5, 6]]

test "#156: expansion in destructuring in comprehensions", ->
  list = [[0, 1, 2], [2, 3, 4], [4, 5, 6]]
  arrayEq (last for [..., last] in list), [2, 4, 6]

test "#3778: Consistently always cache for loop range boundaries and steps, even
      if they are simple identifiers", ->
  a = 1; arrayEq [1, 2, 3], (for n in [1, 2, 3] by  a then a = 4; n)
  a = 1; arrayEq [1, 2, 3], (for n in [1, 2, 3] by +a then a = 4; n)
  a = 1; arrayEq [1, 2, 3], (for n in [a..3]          then a = 4; n)
  a = 1; arrayEq [1, 2, 3], (for n in [+a..3]         then a = 4; n)
  a = 3; arrayEq [1, 2, 3], (for n in [1..a]          then a = 4; n)
  a = 3; arrayEq [1, 2, 3], (for n in [1..+a]         then a = 4; n)
  a = 1; arrayEq [1, 2, 3], (for n in [1..3] by  a    then a = 4; n)
  a = 1; arrayEq [1, 2, 3], (for n in [1..3] by +a    then a = 4; n)

</script>
<script type="text/x-coffeescript" class="test" id="control_flow">
# Control Flow
# ------------

# * Conditionals
# * Loops
#   * For
#   * While
#   * Until
#   * Loop
# * Switch
# * Throw

# TODO: make sure postfix forms and expression coercion are properly tested

# shared identity function
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)

# Conditionals

test "basic conditionals", ->
  if false
    ok false
  else if false
    ok false
  else
    ok true

  if true
    ok true
  else if true
    ok false
  else
    ok true

  unless true
    ok false
  else unless true
    ok false
  else
    ok true

  unless false
    ok true
  else unless false
    ok false
  else
    ok true

test "single-line conditional", ->
  if false then ok false else ok true
  unless false then ok true else ok false

test "nested conditionals", ->
  nonce = {}
  eq nonce, (if true
    unless false
      if false then false else
        if true
          nonce)

test "nested single-line conditionals", ->
  nonce = {}

  a = if false then undefined else b = if 0 then undefined else nonce
  eq nonce, a
  eq nonce, b

  c = if false then undefined else (if 0 then undefined else nonce)
  eq nonce, c

  d = if true then id(if false then undefined else nonce)
  eq nonce, d

test "empty conditional bodies", ->
  eq undefined, (if false
  else if false
  else)

test "conditional bodies containing only comments", ->
  eq undefined, (if true
    ###
    block comment
    ###
  else
    # comment
  )

  eq undefined, (if false
    # comment
  else if true
    ###
    block comment
    ###
  else)

test "return value of if-else is from the proper body", ->
  nonce = {}
  eq nonce, if false then undefined else nonce

test "return value of unless-else is from the proper body", ->
  nonce = {}
  eq nonce, unless true then undefined else nonce

test "assign inside the condition of a conditional statement", ->
  nonce = {}
  if a = nonce then 1
  eq nonce, a
  1 if b = nonce
  eq nonce, b


# Interactions With Functions

test "single-line function definition with single-line conditional", ->
  fn = -> if 1 < 0.5 then 1 else -1
  ok fn() is -1

test "function resturns conditional value with no `else`", ->
  fn = ->
    return if false then true
  eq undefined, fn()

test "function returns a conditional value", ->
  a = {}
  fnA = ->
    return if false then undefined else a
  eq a, fnA()

  b = {}
  fnB = ->
    return unless false then b else undefined
  eq b, fnB()

test "passing a conditional value to a function", ->
  nonce = {}
  eq nonce, id if false then undefined else nonce

test "unmatched `then` should catch implicit calls", ->
  a = 0
  trueFn = -> true
  if trueFn undefined then a++
  eq 1, a


# if-to-ternary

test "if-to-ternary with instanceof requires parentheses", ->
  nonce = {}
  eq nonce, (if {} instanceof Object
    nonce
  else
    undefined)

test "if-to-ternary as part of a larger operation requires parentheses", ->
  ok 2, 1 + if false then 0 else 1


# Odd Formatting

test "if-else indented within an assignment", ->
  nonce = {}
  result =
    if false
      undefined
    else
      nonce
  eq nonce, result

test "suppressed indentation via assignment", ->
  nonce = {}
  result =
    if      false then undefined
    else if no    then undefined
    else if 0     then undefined
    else if 1 < 0 then undefined
    else               id(
         if false then undefined
         else          nonce
    )
  eq nonce, result

test "tight formatting with leading `then`", ->
  nonce = {}
  eq nonce,
  if true
  then nonce
  else undefined

test "#738: inline function defintion", ->
  nonce = {}
  fn = if true then -> nonce
  eq nonce, fn()

test "#748: trailing reserved identifiers", ->
  nonce = {}
  obj = delete: true
  result = if obj.delete
    nonce
  eq nonce, result

test 'if-else within an assignment, condition parenthesized', ->
  result = if (1 is 1) then 'correct'
  eq result, 'correct'

  result = if ('whatever' ? no) then 'correct'
  eq result, 'correct'

  f = -> 'wrong'
  result = if (f?()) then 'correct' else 'wrong'
  eq result, 'correct'

# Postfix

test "#3056: multiple postfix conditionals", ->
  temp = 'initial'
  temp = 'ignored' unless true if false
  eq temp, 'initial'

# Loops

test "basic `while` loops", ->

  i = 5
  list = while i -= 1
    i * 2
  ok list.join(' ') is "8 6 4 2"

  i = 5
  list = (i * 3 while i -= 1)
  ok list.join(' ') is "12 9 6 3"

  i = 5
  func   = (num) -> i -= num
  assert = -> ok i < 5 > 0
  results = while func 1
    assert()
    i
  ok results.join(' ') is '4 3 2 1'

  i = 10
  results = while i -= 1 when i % 2 is 0
    i * 2
  ok results.join(' ') is '16 12 8 4'


test "Issue 759: `if` within `while` condition", ->

  2 while if 1 then 0


test "assignment inside the condition of a `while` loop", ->

  nonce = {}
  count = 1
  a = nonce while count--
  eq nonce, a
  count = 1
  while count--
    b = nonce
  eq nonce, b


test "While over break.", ->

  i = 0
  result = while i < 10
    i++
    break
  arrayEq result, []


test "While over continue.", ->

  i = 0
  result = while i < 10
    i++
    continue
  arrayEq result, []


test "Basic `until`", ->

  value = false
  i = 0
  results = until value
    value = true if i is 5
    i++
  ok i is 6


test "Basic `loop`", ->

  i = 5
  list = []
  loop
    i -= 1
    break if i is 0
    list.push i * 2
  ok list.join(' ') is '8 6 4 2'


test "break at the top level", ->
  for i in [1,2,3]
    result = i
    if i == 2
      break
  eq 2, result

test "break *not* at the top level", ->
  someFunc = ->
    i = 0
    while ++i < 3
      result = i
      break if i > 1
    result
  eq 2, someFunc()

# Switch

test "basic `switch`", ->

  num = 10
  result = switch num
    when 5 then false
    when 'a'
      true
      true
      false
    when 10 then true


    # Mid-switch comment with whitespace
    # and multi line
    when 11 then false
    else false

  ok result


  func = (num) ->
    switch num
      when 2, 4, 6
        true
      when 1, 3, 5
        false

  ok func(2)
  ok func(6)
  ok !func(3)
  eq func(8), undefined


test "Ensure that trailing switch elses don't get rewritten.", ->

  result = false
  switch "word"
    when "one thing"
      doSomething()
    else
      result = true unless false

  ok result

  result = false
  switch "word"
    when "one thing"
      doSomething()
    when "other thing"
      doSomething()
    else
      result = true unless false

  ok result


test "Should be able to handle switches sans-condition.", ->

  result = switch
    when null                     then 0
    when !1                       then 1
    when '' not of {''}           then 2
    when [] not instanceof Array  then 3
    when true is false            then 4
    when 'x' < 'y' > 'z'          then 5
    when 'a' in ['b', 'c']        then 6
    when 'd' in (['e', 'f'])      then 7
    else ok

  eq result, ok


test "Should be able to use `@properties` within the switch clause.", ->

  obj = {
    num: 101
    func: ->
      switch @num
        when 101 then '101!'
        else 'other'
  }

  ok obj.func() is '101!'


test "Should be able to use `@properties` within the switch cases.", ->

  obj = {
    num: 101
    func: (yesOrNo) ->
      result = switch yesOrNo
        when yes then @num
        else 'other'
      result
  }

  ok obj.func(yes) is 101


test "Switch with break as the return value of a loop.", ->

  i = 10
  results = while i > 0
    i--
    switch i % 2
      when 1 then i
      when 0 then break

  eq results.join(', '), '9, 7, 5, 3, 1'


test "Issue #997. Switch doesn't fallthrough.", ->

  val = 1
  switch true
    when true
      if false
        return 5
    else
      val = 2

  eq val, 1

# Throw

test "Throw should be usable as an expression.", ->
  try
    false or throw 'up'
    throw new Error 'failed'
  catch e
    ok e is 'up'


test "#2555, strange function if bodies", ->
  success = -> ok true
  failure = -> ok false

  success() if do ->
    yes

  failure() if try
    false

test "#1057: `catch` or `finally` in single-line functions", ->
  ok do -> try throw 'up' catch then yes
  ok do -> try yes finally 'nothing'

test "#2367: super in for-loop", ->
  class Foo
    sum: 0
    add: (val) -> @sum += val

  class Bar extends Foo
    add: (vals...) ->
      super val for val in vals
      @sum

  eq 10, (new Bar).add 2, 3, 5

test "#4267: lots of for-loops in the same scope", ->
  # This used to include the invalid JavaScript `var do = 0`.
  code = """
    do ->
      #{Array(200).join('for [0..0] then\n  ')}
      true
  """
  ok CoffeeScript.eval(code)

</script>
<script type="text/x-coffeescript" class="test" id="error_messages">
# Error Formatting
# ----------------

# Ensure that errors of different kinds (lexer, parser and compiler) are shown
# in a consistent way.

assertErrorFormat = (code, expectedErrorFormat) ->
  throws (-> CoffeeScript.run code), (err) ->
    err.colorful = no
    eq expectedErrorFormat, "#{err}"
    yes

test "lexer errors formatting", ->
  assertErrorFormat '''
    normalObject    = {}
    insideOutObject = }{
  ''',
  '''
    [stdin]:2:19: error: unmatched }
    insideOutObject = }{
                      ^
  '''

test "parser error formatting", ->
  assertErrorFormat '''
    foo in bar or in baz
  ''',
  '''
    [stdin]:1:15: error: unexpected in
    foo in bar or in baz
                  ^^
  '''

test "compiler error formatting", ->
  assertErrorFormat '''
    evil = (foo, eval, bar) ->
  ''',
  '''
    [stdin]:1:14: error: 'eval' can't be assigned
    evil = (foo, eval, bar) ->
                 ^^^^
  '''

test "compiler error formatting with mixed tab and space", ->
  assertErrorFormat """
    \t  if a
    \t  test
  """,
  '''
    [stdin]:1:4: error: unexpected if
    \t  if a
    \t  ^^
  '''


if require?
  os   = require 'os'
  fs   = require 'fs'
  path = require 'path'

  test "patchStackTrace line patching", ->
    err = new Error 'error'
    ok err.stack.match /test[\/\\]error_messages\.coffee:\d+:\d+\b/

  test "patchStackTrace stack prelude consistent with V8", ->
    err = new Error
    ok err.stack.match /^Error\n/ # Notice no colon when no message.

    err = new Error 'error'
    ok err.stack.match /^Error: error\n/

  test "#2849: compilation error in a require()d file", ->
    # Create a temporary file to require().
    tempFile = path.join os.tmpdir(), 'syntax-error.coffee'
    ok not fs.existsSync tempFile
    fs.writeFileSync tempFile, 'foo in bar or in baz'

    try
      assertErrorFormat """
        require '#{tempFile}'
      """,
      """
        #{fs.realpathSync tempFile}:1:15: error: unexpected in
        foo in bar or in baz
                      ^^
      """
    finally
      fs.unlinkSync tempFile

  test "#3890 Error.prepareStackTrace doesn't throw an error if a compiled file is deleted", ->
    # Adapted from https://github.com/atom/coffee-cash/blob/master/spec/coffee-cash-spec.coffee
    filePath = path.join os.tmpdir(), 'PrepareStackTraceTestFile.coffee'
    fs.writeFileSync filePath, "module.exports = -> throw new Error('hello world')"
    throwsAnError = require filePath
    fs.unlinkSync filePath

    try
      throwsAnError()
    catch error

    eq error.message, 'hello world'
    doesNotThrow(-> error.stack)
    notEqual error.stack.toString().indexOf(filePath), -1

  test "#4418 stack traces for compiled files reference the correct line number", ->
    filePath = path.join os.tmpdir(), 'StackTraceLineNumberTestFile.coffee'
    fileContents = """
      testCompiledFileStackTraceLineNumber = ->
        # `a` on the next line is undefined and should throw a ReferenceError
        console.log a if true

      do testCompiledFileStackTraceLineNumber
      """
    fs.writeFileSync filePath, fileContents

    try
      require filePath
    catch error
    fs.unlinkSync filePath

    # Make sure the line number reported is line 3 (the original Coffee source)
    # and not line 6 (the generated JavaScript).
    eq /StackTraceLineNumberTestFile.coffee:(\d)/.exec(error.stack.toString())[1], '3'


test "#4418 stack traces for compiled strings reference the correct line number", ->
  try
    CoffeeScript.run """
      testCompiledStringStackTraceLineNumber = ->
        # `a` on the next line is undefined and should throw a ReferenceError
        console.log a if true

      do testCompiledStringStackTraceLineNumber
      """
  catch error

  # Make sure the line number reported is line 3 (the original Coffee source)
  # and not line 6 (the generated JavaScript).
  eq /at testCompiledStringStackTraceLineNumber.*:(\d):/.exec(error.stack.toString())[1], '3'


test "#1096: unexpected generated tokens", ->
  # Implicit ends
  assertErrorFormat 'a:, b', '''
    [stdin]:1:3: error: unexpected ,
    a:, b
      ^
  '''
  # Explicit ends
  assertErrorFormat '(a:)', '''
    [stdin]:1:4: error: unexpected )
    (a:)
       ^
  '''
  # Unexpected end of file
  assertErrorFormat 'a:', '''
    [stdin]:1:3: error: unexpected end of input
    a:
      ^
  '''
  assertErrorFormat 'a +', '''
    [stdin]:1:4: error: unexpected end of input
    a +
       ^
  '''
  # Unexpected key in implicit object (an implicit object itself is _not_
  # unexpected here)
  assertErrorFormat '''
    for i in [1]:
      1
  ''', '''
    [stdin]:1:10: error: unexpected [
    for i in [1]:
             ^
  '''
  # Unexpected regex
  assertErrorFormat '{/a/i: val}', '''
    [stdin]:1:2: error: unexpected regex
    {/a/i: val}
     ^^^^
  '''
  assertErrorFormat '{///a///i: val}', '''
    [stdin]:1:2: error: unexpected regex
    {///a///i: val}
     ^^^^^^^^
  '''
  assertErrorFormat '{///#{a}///i: val}', '''
    [stdin]:1:2: error: unexpected regex
    {///#{a}///i: val}
     ^^^^^^^^^^^
  '''
  # Unexpected string
  assertErrorFormat 'import foo from "lib-#{version}"', '''
    [stdin]:1:17: error: the name of the module to be imported from must be an uninterpolated string
    import foo from "lib-#{version}"
                    ^^^^^^^^^^^^^^^^
  '''

  # Unexpected number
  assertErrorFormat '"a"0x00Af2', '''
    [stdin]:1:4: error: unexpected number
    "a"0x00Af2
       ^^^^^^^
  '''

test "#1316: unexpected end of interpolation", ->
  assertErrorFormat '''
    "#{+}"
  ''', '''
    [stdin]:1:5: error: unexpected end of interpolation
    "#{+}"
        ^
  '''
  assertErrorFormat '''
    "#{++}"
  ''', '''
    [stdin]:1:6: error: unexpected end of interpolation
    "#{++}"
         ^
  '''
  assertErrorFormat '''
    "#{-}"
  ''', '''
    [stdin]:1:5: error: unexpected end of interpolation
    "#{-}"
        ^
  '''
  assertErrorFormat '''
    "#{--}"
  ''', '''
    [stdin]:1:6: error: unexpected end of interpolation
    "#{--}"
         ^
  '''
  assertErrorFormat '''
    "#{~}"
  ''', '''
    [stdin]:1:5: error: unexpected end of interpolation
    "#{~}"
        ^
  '''
  assertErrorFormat '''
    "#{!}"
  ''', '''
    [stdin]:1:5: error: unexpected end of interpolation
    "#{!}"
        ^
  '''
  assertErrorFormat '''
    "#{not}"
  ''', '''
    [stdin]:1:7: error: unexpected end of interpolation
    "#{not}"
          ^
  '''
  assertErrorFormat '''
    "#{5) + (4}_"
  ''', '''
    [stdin]:1:5: error: unmatched )
    "#{5) + (4}_"
        ^
  '''
  # #2918
  assertErrorFormat '''
    "#{foo.}"
  ''', '''
    [stdin]:1:8: error: unexpected end of interpolation
    "#{foo.}"
           ^
  '''

test "#3325: implicit indentation errors", ->
  assertErrorFormat '''
    i for i in a then i
  ''', '''
    [stdin]:1:14: error: unexpected then
    i for i in a then i
                 ^^^^
  '''

test "explicit indentation errors", ->
  assertErrorFormat '''
    a = b
      c
  ''', '''
    [stdin]:2:1: error: unexpected indentation
      c
    ^^
  '''

test "unclosed strings", ->
  assertErrorFormat '''
    '
  ''', '''
    [stdin]:1:1: error: missing '
    '
    ^
  '''
  assertErrorFormat '''
    "
  ''', '''
    [stdin]:1:1: error: missing "
    "
    ^
  '''
  assertErrorFormat """
    '''
  """, """
    [stdin]:1:1: error: missing '''
    '''
    ^^^
  """
  assertErrorFormat '''
    """
  ''', '''
    [stdin]:1:1: error: missing """
    """
    ^^^
  '''
  assertErrorFormat '''
    "#{"
  ''', '''
    [stdin]:1:4: error: missing "
    "#{"
       ^
  '''
  assertErrorFormat '''
    """#{"
  ''', '''
    [stdin]:1:6: error: missing "
    """#{"
         ^
  '''
  assertErrorFormat '''
    "#{"""
  ''', '''
    [stdin]:1:4: error: missing """
    "#{"""
       ^^^
  '''
  assertErrorFormat '''
    """#{"""
  ''', '''
    [stdin]:1:6: error: missing """
    """#{"""
         ^^^
  '''
  assertErrorFormat '''
    ///#{"""
  ''', '''
    [stdin]:1:6: error: missing """
    ///#{"""
         ^^^
  '''
  assertErrorFormat '''
    "a
      #{foo """
        bar
          #{ +'12 }
        baz
        """} b"
  ''', '''
    [stdin]:4:11: error: missing '
          #{ +'12 }
              ^
  '''
  # https://github.com/jashkenas/coffeescript/issues/3301#issuecomment-31735168
  assertErrorFormat '''
    # Note the double escaping; this would be `"""a\"""` real code.
    """a\\"""
  ''', '''
    [stdin]:2:1: error: missing """
    """a\\"""
    ^^^
  '''

test "unclosed heregexes", ->
  assertErrorFormat '''
    ///
  ''', '''
    [stdin]:1:1: error: missing ///
    ///
    ^^^
  '''
  # https://github.com/jashkenas/coffeescript/issues/3301#issuecomment-31735168
  assertErrorFormat '''
    # Note the double escaping; this would be `///a\///` real code.
    ///a\\///
  ''', '''
    [stdin]:2:1: error: missing ///
    ///a\\///
    ^^^
  '''

test "unexpected token after string", ->
  # Parsing error.
  assertErrorFormat '''
    'foo'bar
  ''', '''
    [stdin]:1:6: error: unexpected identifier
    'foo'bar
         ^^^
  '''
  assertErrorFormat '''
    "foo"bar
  ''', '''
    [stdin]:1:6: error: unexpected identifier
    "foo"bar
         ^^^
  '''
  # Lexing error.
  assertErrorFormat '''
    'foo'bar'
  ''', '''
    [stdin]:1:9: error: missing '
    'foo'bar'
            ^
  '''
  assertErrorFormat '''
    "foo"bar"
  ''', '''
    [stdin]:1:9: error: missing "
    "foo"bar"
            ^
  '''

test "#3348: Location data is wrong in interpolations with leading whitespace", ->
  assertErrorFormat '''
    "#{ * }"
  ''', '''
    [stdin]:1:5: error: unexpected *
    "#{ * }"
        ^
  '''

test "octal escapes", ->
  assertErrorFormat '''
    "a\\0\\tb\\\\\\07c"
  ''', '''
    [stdin]:1:10: error: octal escape sequences are not allowed \\07
    "a\\0\\tb\\\\\\07c"
      \  \   \ \ ^\^^
  '''
  assertErrorFormat '''
    "a
      #{b} \\1"
  ''', '''
    [stdin]:2:8: error: octal escape sequences are not allowed \\1
      #{b} \\1"
           ^\^
  '''
  assertErrorFormat '''
    /a\\0\\tb\\\\\\07c/
  ''', '''
    [stdin]:1:10: error: octal escape sequences are not allowed \\07
    /a\\0\\tb\\\\\\07c/
      \  \   \ \ ^\^^
  '''
  assertErrorFormat '''
    /a\\1\\tb\\\\\\07c/
  ''', '''
    [stdin]:1:10: error: octal escape sequences are not allowed \\07
    /a\\1\\tb\\\\\\07c/
      \  \   \ \ ^\^^
  '''
  assertErrorFormat '''
    ///a
      #{b} \\01///
  ''', '''
    [stdin]:2:8: error: octal escape sequences are not allowed \\01
      #{b} \\01///
           ^\^^
  '''

test "#3795: invalid escapes", ->
  assertErrorFormat '''
    "a\\0\\tb\\\\\\x7g"
  ''', '''
    [stdin]:1:10: error: invalid escape sequence \\x7g
    "a\\0\\tb\\\\\\x7g"
      \  \   \ \ ^\^^^
  '''
  assertErrorFormat '''
    "a
      #{b} \\uA02
     c"
  ''', '''
    [stdin]:2:8: error: invalid escape sequence \\uA02
      #{b} \\uA02
           ^\^^^^
  '''
  assertErrorFormat '''
    /a\\u002space/
  ''', '''
    [stdin]:1:3: error: invalid escape sequence \\u002s
    /a\\u002space/
      ^\^^^^^
  '''
  assertErrorFormat '''
    ///a \\u002 0 space///
  ''', '''
    [stdin]:1:6: error: invalid escape sequence \\u002 \n\
    ///a \\u002 0 space///
         ^\^^^^^
  '''
  assertErrorFormat '''
    ///a
      #{b} \\x0
     c///
  ''', '''
    [stdin]:2:8: error: invalid escape sequence \\x0
      #{b} \\x0
           ^\^^
  '''
  assertErrorFormat '''
    /ab\\u/
  ''', '''
    [stdin]:1:4: error: invalid escape sequence \\u
    /ab\\u/
       ^\^
  '''

test "illegal herecomment", ->
  assertErrorFormat '''
    ###
      Regex: /a*/g
    ###
  ''', '''
    [stdin]:2:12: error: block comments cannot contain */
      Regex: /a*/g
               ^^
  '''

test "#1724: regular expressions beginning with *", ->
  assertErrorFormat '''
    /* foo/
  ''', '''
    [stdin]:1:2: error: regular expressions cannot begin with *
    /* foo/
     ^
  '''
  assertErrorFormat '''
    ///
      * foo
    ///
  ''', '''
    [stdin]:2:3: error: regular expressions cannot begin with *
      * foo
      ^
  '''

test "invalid regex flags", ->
  assertErrorFormat '''
    /a/ii
  ''', '''
    [stdin]:1:4: error: invalid regular expression flags ii
    /a/ii
       ^^
  '''
  assertErrorFormat '''
    /a/G
  ''', '''
    [stdin]:1:4: error: invalid regular expression flags G
    /a/G
       ^
  '''
  assertErrorFormat '''
    /a/gimi
  ''', '''
    [stdin]:1:4: error: invalid regular expression flags gimi
    /a/gimi
       ^^^^
  '''
  assertErrorFormat '''
    /a/g_
  ''', '''
    [stdin]:1:4: error: invalid regular expression flags g_
    /a/g_
       ^^
  '''
  assertErrorFormat '''
    ///a///ii
  ''', '''
    [stdin]:1:8: error: invalid regular expression flags ii
    ///a///ii
           ^^
  '''
  doesNotThrow -> CoffeeScript.compile '/a/ymgi'

test "missing `)`, `}`, `]`", ->
  assertErrorFormat '''
    (
  ''', '''
    [stdin]:1:1: error: missing )
    (
    ^
  '''
  assertErrorFormat '''
    {
  ''', '''
    [stdin]:1:1: error: missing }
    {
    ^
  '''
  assertErrorFormat '''
    [
  ''', '''
    [stdin]:1:1: error: missing ]
    [
    ^
  '''
  assertErrorFormat '''
    obj = {a: [1, (2+
  ''', '''
    [stdin]:1:15: error: missing )
    obj = {a: [1, (2+
                  ^
  '''
  assertErrorFormat '''
    "#{
  ''', '''
    [stdin]:1:3: error: missing }
    "#{
      ^
  '''
  assertErrorFormat '''
    """
      foo#{ bar "#{1}"
  ''', '''
    [stdin]:2:7: error: missing }
      foo#{ bar "#{1}"
          ^
  '''

test "unclosed regexes", ->
  assertErrorFormat '''
    /
  ''', '''
    [stdin]:1:1: error: missing / (unclosed regex)
    /
    ^
  '''
  assertErrorFormat '''
    # Note the double escaping; this would be `/a\/` real code.
    /a\\/
  ''', '''
    [stdin]:2:1: error: missing / (unclosed regex)
    /a\\/
    ^
  '''
  assertErrorFormat '''
    /// ^
      a #{""" ""#{if /[/].test "|" then 1 else 0}"" """}
    ///
  ''', '''
    [stdin]:2:18: error: missing / (unclosed regex)
      a #{""" ""#{if /[/].test "|" then 1 else 0}"" """}
                     ^
  '''

test "duplicate function arguments", ->
  assertErrorFormat '''
    (foo, bar, foo) ->
  ''', '''
    [stdin]:1:12: error: multiple parameters named foo
    (foo, bar, foo) ->
               ^^^
  '''
  assertErrorFormat '''
    (@foo, bar, @foo) ->
  ''', '''
    [stdin]:1:13: error: multiple parameters named @foo
    (@foo, bar, @foo) ->
                ^^^^
  '''

test "reserved words", ->
  assertErrorFormat '''
    case
  ''', '''
    [stdin]:1:1: error: reserved word 'case'
    case
    ^^^^
  '''
  assertErrorFormat '''
    case = 1
  ''', '''
    [stdin]:1:1: error: reserved word 'case'
    case = 1
    ^^^^
  '''
  assertErrorFormat '''
    for = 1
  ''', '''
    [stdin]:1:1: error: keyword 'for' can't be assigned
    for = 1
    ^^^
  '''
  assertErrorFormat '''
    unless = 1
  ''', '''
    [stdin]:1:1: error: keyword 'unless' can't be assigned
    unless = 1
    ^^^^^^
  '''
  assertErrorFormat '''
    for += 1
  ''', '''
    [stdin]:1:1: error: keyword 'for' can't be assigned
    for += 1
    ^^^
  '''
  assertErrorFormat '''
    for &&= 1
  ''', '''
    [stdin]:1:1: error: keyword 'for' can't be assigned
    for &&= 1
    ^^^
  '''
  # Make sure token look-behind doesn't go out of range.
  assertErrorFormat '''
    &&= 1
  ''', '''
    [stdin]:1:1: error: unexpected &&=
    &&= 1
    ^^^
  '''
  # #2306: Show unaliased name in error messages.
  assertErrorFormat '''
    on = 1
  ''', '''
    [stdin]:1:1: error: keyword 'on' can't be assigned
    on = 1
    ^^
  '''

test "strict mode errors", ->
  assertErrorFormat '''
    eval = 1
  ''', '''
    [stdin]:1:1: error: 'eval' can't be assigned
    eval = 1
    ^^^^
  '''
  assertErrorFormat '''
    class eval
  ''', '''
    [stdin]:1:7: error: 'eval' can't be assigned
    class eval
          ^^^^
  '''
  assertErrorFormat '''
    arguments++
  ''', '''
    [stdin]:1:1: error: 'arguments' can't be assigned
    arguments++
    ^^^^^^^^^
  '''
  assertErrorFormat '''
    --arguments
  ''', '''
    [stdin]:1:3: error: 'arguments' can't be assigned
    --arguments
      ^^^^^^^^^
  '''

test "invalid numbers", ->
  assertErrorFormat '''
    0X0
  ''', '''
    [stdin]:1:2: error: radix prefix in '0X0' must be lowercase
    0X0
     ^
  '''
  assertErrorFormat '''
    10E0
  ''', '''
    [stdin]:1:3: error: exponential notation in '10E0' must be indicated with a lowercase 'e'
    10E0
      ^
  '''
  assertErrorFormat '''
    018
  ''', '''
    [stdin]:1:1: error: decimal literal '018' must not be prefixed with '0'
    018
    ^^^
  '''
  assertErrorFormat '''
    010
  ''', '''
    [stdin]:1:1: error: octal literal '010' must be prefixed with '0o'
    010
    ^^^
'''

test "unexpected object keys", ->
  assertErrorFormat '''
    {[[]]}
  ''', '''
    [stdin]:1:2: error: unexpected [
    {[[]]}
     ^
  '''
  assertErrorFormat '''
    {[[]]: 1}
  ''', '''
    [stdin]:1:2: error: unexpected [
    {[[]]: 1}
     ^
  '''
  assertErrorFormat '''
    [[]]: 1
  ''', '''
    [stdin]:1:1: error: unexpected [
    [[]]: 1
    ^
  '''
  assertErrorFormat '''
    {(a + "b")}
  ''', '''
    [stdin]:1:2: error: unexpected (
    {(a + "b")}
     ^
  '''
  assertErrorFormat '''
    {(a + "b"): 1}
  ''', '''
    [stdin]:1:2: error: unexpected (
    {(a + "b"): 1}
     ^
  '''
  assertErrorFormat '''
    (a + "b"): 1
  ''', '''
    [stdin]:1:1: error: unexpected (
    (a + "b"): 1
    ^
  '''
  assertErrorFormat '''
    a: 1, [[]]: 2
  ''', '''
    [stdin]:1:7: error: unexpected [
    a: 1, [[]]: 2
          ^
  '''
  assertErrorFormat '''
    {a: 1, [[]]: 2}
  ''', '''
    [stdin]:1:8: error: unexpected [
    {a: 1, [[]]: 2}
           ^
  '''

test "invalid object keys", ->
  assertErrorFormat '''
    @a: 1
  ''', '''
    [stdin]:1:1: error: invalid object key
    @a: 1
    ^^
  '''
  assertErrorFormat '''
    f
      @a: 1
  ''', '''
    [stdin]:2:3: error: invalid object key
      @a: 1
      ^^
  '''
  assertErrorFormat '''
    {a=2}
  ''', '''
    [stdin]:1:3: error: unexpected =
    {a=2}
      ^
  '''

test "invalid destructuring default target", ->
  assertErrorFormat '''
    {'a' = 2} = obj
  ''', '''
    [stdin]:1:6: error: unexpected =
    {'a' = 2} = obj
         ^
  '''

test "#4070: lone expansion", ->
  assertErrorFormat '''
    [...] = a
  ''', '''
    [stdin]:1:2: error: Destructuring assignment has no target
    [...] = a
     ^^^
  '''
  assertErrorFormat '''
    [ ..., ] = a
  ''', '''
    [stdin]:1:3: error: Destructuring assignment has no target
    [ ..., ] = a
      ^^^
  '''

test "#3926: implicit object in parameter list", ->
  assertErrorFormat '''
    (a: b) ->
  ''', '''
    [stdin]:1:3: error: unexpected :
    (a: b) ->
      ^
  '''
  assertErrorFormat '''
    (one, two, {three, four: five}, key: value) ->
  ''', '''
    [stdin]:1:36: error: unexpected :
    (one, two, {three, four: five}, key: value) ->
                                       ^
  '''

test "#4130: unassignable in destructured param", ->
  assertErrorFormat '''
    fun = ({
      @param : null
    }) ->
      console.log "Oh hello!"
  ''', '''
    [stdin]:2:12: error: keyword 'null' can't be assigned
      @param : null
               ^^^^
  '''
  assertErrorFormat '''
    ({a: null}) ->
  ''', '''
    [stdin]:1:6: error: keyword 'null' can't be assigned
    ({a: null}) ->
         ^^^^
  '''
  assertErrorFormat '''
    ({a: 1}) ->
  ''', '''
    [stdin]:1:6: error: '1' can't be assigned
    ({a: 1}) ->
         ^
  '''
  assertErrorFormat '''
    ({1}) ->
  ''', '''
    [stdin]:1:3: error: '1' can't be assigned
    ({1}) ->
      ^
  '''
  assertErrorFormat '''
    ({a: true = 1}) ->
  ''', '''
    [stdin]:1:6: error: keyword 'true' can't be assigned
    ({a: true = 1}) ->
         ^^^^
  '''

test "`yield` outside of a function", ->
  assertErrorFormat '''
    yield 1
  ''', '''
    [stdin]:1:1: error: yield can only occur inside functions
    yield 1
    ^^^^^^^
  '''
  assertErrorFormat '''
    yield return
  ''', '''
    [stdin]:1:1: error: yield can only occur inside functions
    yield return
    ^^^^^^^^^^^^
  '''

test "#4097: `yield return` as an expression", ->
  assertErrorFormat '''
    -> (yield return)
  ''', '''
    [stdin]:1:5: error: cannot use a pure statement in an expression
    -> (yield return)
        ^^^^^^^^^^^^
  '''

test "`&&=` and `||=` with a space in-between", ->
  assertErrorFormat '''
    a = 0
    a && = 1
  ''', '''
    [stdin]:2:6: error: unexpected =
    a && = 1
         ^
  '''
  assertErrorFormat '''
    a = 0
    a and = 1
  ''', '''
    [stdin]:2:7: error: unexpected =
    a and = 1
          ^
  '''
  assertErrorFormat '''
    a = 0
    a || = 1
  ''', '''
    [stdin]:2:6: error: unexpected =
    a || = 1
         ^
  '''
  assertErrorFormat '''
    a = 0
    a or = 1
  ''', '''
    [stdin]:2:6: error: unexpected =
    a or = 1
         ^
  '''

test "anonymous functions cannot be exported", ->
  assertErrorFormat '''
    export ->
      console.log 'hello, world!'
  ''', '''
    [stdin]:1:8: error: unexpected ->
    export ->
           ^^
  '''

test "anonymous classes cannot be exported", ->
  assertErrorFormat '''
    export class
      constructor: ->
        console.log 'hello, world!'
  ''', '''
    [stdin]:1:8: error: anonymous classes cannot be exported
    export class
           ^^^^^
  '''

test "unless enclosed by curly braces, only * can be aliased", ->
  assertErrorFormat '''
    import foo as bar from 'lib'
  ''', '''
    [stdin]:1:12: error: unexpected as
    import foo as bar from 'lib'
               ^^
  '''

test "unwrapped imports must follow constrained syntax", ->
  assertErrorFormat '''
    import foo, bar from 'lib'
  ''', '''
    [stdin]:1:13: error: unexpected identifier
    import foo, bar from 'lib'
                ^^^
  '''
  assertErrorFormat '''
    import foo, bar, baz from 'lib'
  ''', '''
    [stdin]:1:13: error: unexpected identifier
    import foo, bar, baz from 'lib'
                ^^^
  '''
  assertErrorFormat '''
    import foo, bar as baz from 'lib'
  ''', '''
    [stdin]:1:13: error: unexpected identifier
    import foo, bar as baz from 'lib'
                ^^^
  '''

test "cannot export * without a module to export from", ->
  assertErrorFormat '''
    export *
  ''', '''
    [stdin]:1:9: error: unexpected end of input
    export *
            ^
  '''

test "imports and exports must be top-level", ->
  assertErrorFormat '''
    if foo
      import { bar } from 'lib'
  ''', '''
    [stdin]:2:3: error: import statements must be at top-level scope
      import { bar } from 'lib'
      ^^^^^^^^^^^^^^^^^^^^^^^^^
  '''
  assertErrorFormat '''
    foo = ->
      export { bar }
  ''', '''
    [stdin]:2:3: error: export statements must be at top-level scope
      export { bar }
      ^^^^^^^^^^^^^^
  '''

test "cannot import the same member more than once", ->
  assertErrorFormat '''
    import { foo, foo } from 'lib'
  ''', '''
    [stdin]:1:15: error: 'foo' has already been declared
    import { foo, foo } from 'lib'
                  ^^^
  '''
  assertErrorFormat '''
    import { foo, bar, foo } from 'lib'
  ''', '''
    [stdin]:1:20: error: 'foo' has already been declared
    import { foo, bar, foo } from 'lib'
                       ^^^
  '''
  assertErrorFormat '''
    import { foo, bar as foo } from 'lib'
  ''', '''
    [stdin]:1:15: error: 'foo' has already been declared
    import { foo, bar as foo } from 'lib'
                  ^^^^^^^^^^
  '''
  assertErrorFormat '''
    import foo, { foo } from 'lib'
  ''', '''
    [stdin]:1:15: error: 'foo' has already been declared
    import foo, { foo } from 'lib'
                  ^^^
  '''
  assertErrorFormat '''
    import foo, { bar as foo } from 'lib'
  ''', '''
    [stdin]:1:15: error: 'foo' has already been declared
    import foo, { bar as foo } from 'lib'
                  ^^^^^^^^^^
  '''
  assertErrorFormat '''
    import foo from 'libA'
    import foo from 'libB'
  ''', '''
    [stdin]:2:8: error: 'foo' has already been declared
    import foo from 'libB'
           ^^^
  '''
  assertErrorFormat '''
    import * as foo from 'libA'
    import { foo } from 'libB'
  ''', '''
    [stdin]:2:10: error: 'foo' has already been declared
    import { foo } from 'libB'
             ^^^
  '''

test "imported members cannot be reassigned", ->
  assertErrorFormat '''
    import { foo } from 'lib'
    foo = 'bar'
  ''', '''
    [stdin]:2:1: error: 'foo' is read-only
    foo = 'bar'
    ^^^
  '''
  assertErrorFormat '''
    import { foo } from 'lib'
    export default foo = 'bar'
  ''', '''
    [stdin]:2:16: error: 'foo' is read-only
    export default foo = 'bar'
                   ^^^
  '''
  assertErrorFormat '''
    import { foo } from 'lib'
    export foo = 'bar'
  ''', '''
    [stdin]:2:8: error: 'foo' is read-only
    export foo = 'bar'
           ^^^
  '''

test "CoffeeScript keywords cannot be used as unaliased names in import lists", ->
  assertErrorFormat """
    import { unless, baz as bar } from 'lib'
    bar.barMethod()
  """, '''
    [stdin]:1:10: error: unexpected unless
    import { unless, baz as bar } from 'lib'
             ^^^^^^
  '''

test "CoffeeScript keywords cannot be used as local names in import list aliases", ->
  assertErrorFormat """
    import { bar as unless, baz as bar } from 'lib'
    bar.barMethod()
  """, '''
    [stdin]:1:17: error: unexpected unless
    import { bar as unless, baz as bar } from 'lib'
                    ^^^^^^
  '''

test "indexes are not supported in for-from loops", ->
  assertErrorFormat "x for x, i from [1, 2, 3]", '''
    [stdin]:1:10: error: cannot use index with for-from
    x for x, i from [1, 2, 3]
             ^
  '''

test "own is not supported in for-from loops", ->
  assertErrorFormat "x for own x from [1, 2, 3]", '''
    [stdin]:1:7: error: cannot use own with for-from
    x for own x from [1, 2, 3]
          ^^^
    '''

test "tagged template literals must be called by an identifier", ->
  assertErrorFormat "1''", '''
    [stdin]:1:1: error: literal is not a function
    1''
    ^
  '''
  assertErrorFormat '1""', '''
    [stdin]:1:1: error: literal is not a function
    1""
    ^
  '''
  assertErrorFormat "1'b'", '''
    [stdin]:1:1: error: literal is not a function
    1'b'
    ^
  '''
  assertErrorFormat '1"b"', '''
    [stdin]:1:1: error: literal is not a function
    1"b"
    ^
  '''
  assertErrorFormat "1'''b'''", """
    [stdin]:1:1: error: literal is not a function
    1'''b'''
    ^
  """
  assertErrorFormat '1"""b"""', '''
    [stdin]:1:1: error: literal is not a function
    1"""b"""
    ^
  '''
  assertErrorFormat '1"#{b}"', '''
    [stdin]:1:1: error: literal is not a function
    1"#{b}"
    ^
  '''
  assertErrorFormat '1"""#{b}"""', '''
    [stdin]:1:1: error: literal is not a function
    1"""#{b}"""
    ^
  '''

test "can't use pattern matches for loop indices", ->
  assertErrorFormat 'a for b, {c} in d', '''
    [stdin]:1:10: error: index cannot be a pattern matching expression
    a for b, {c} in d
             ^^^
  '''

test "#4248: Unicode code point escapes", ->
  assertErrorFormat '''
    "a
      #{b} \\u{G02}
     c"
  ''', '''
    [stdin]:2:8: error: invalid escape sequence \\u{G02}
      #{b} \\u{G02}
           ^\^^^^^^
  '''
  assertErrorFormat '''
    /a\\u{}b/
  ''', '''
    [stdin]:1:3: error: invalid escape sequence \\u{}
    /a\\u{}b/
      ^\^^^
  '''
  assertErrorFormat '''
    ///a \\u{01abc///
  ''', '''
    [stdin]:1:6: error: invalid escape sequence \\u{01abc
    ///a \\u{01abc///
         ^\^^^^^^^
  '''

  assertErrorFormat '''
    /\\u{123} \\u{110000}/
  ''', '''
    [stdin]:1:10: error: unicode code point escapes greater than \\u{10ffff} are not allowed
    /\\u{123} \\u{110000}/
      \       ^\^^^^^^^^^
  '''

  assertErrorFormat '''
    ///abc\\\\\\u{123456}///u
  ''', '''
    [stdin]:1:9: error: unicode code point escapes greater than \\u{10ffff} are not allowed
    ///abc\\\\\\u{123456}///u
           \ \^\^^^^^^^^^
  '''

  assertErrorFormat '''
    """
      \\u{123}
      a
        \\u{00110000}
      #{ 'b' }
    """
  ''', '''
    [stdin]:4:5: error: unicode code point escapes greater than \\u{10ffff} are not allowed
        \\u{00110000}
        ^\^^^^^^^^^^^
  '''

  assertErrorFormat '''
    '\\u{a}\\u{1111110000}'
  ''', '''
    [stdin]:1:7: error: unicode code point escapes greater than \\u{10ffff} are not allowed
    '\\u{a}\\u{1111110000}'
      \    ^\^^^^^^^^^^^^^
  '''

test "#4283: error message for implicit call", ->
  assertErrorFormat '''
    console.log {search, users, contacts users_to_display}
  ''', '''
    [stdin]:1:29: error: unexpected implicit function call
    console.log {search, users, contacts users_to_display}
                                ^^^^^^^^
  '''

test "#3199: error message for call indented non-object", ->
  assertErrorFormat '''
    fn = ->
    fn
      1
  ''', '''
    [stdin]:3:1: error: unexpected indentation
      1
    ^^
  '''

test "#3199: error message for call indented comprehension", ->
  assertErrorFormat '''
    fn = ->
    fn
      x for x in [1, 2, 3]
  ''', '''
    [stdin]:3:1: error: unexpected indentation
      x for x in [1, 2, 3]
    ^^
  '''

test "#3199: error message for return indented non-object", ->
  assertErrorFormat '''
    return
      1
  ''', '''
    [stdin]:2:3: error: unexpected number
      1
      ^
  '''

test "#3199: error message for return indented comprehension", ->
  assertErrorFormat '''
    return
      x for x in [1, 2, 3]
  ''', '''
    [stdin]:2:3: error: unexpected identifier
      x for x in [1, 2, 3]
      ^
  '''

</script>
<script type="text/x-coffeescript" class="test" id="eval">
if vm = require? 'vm'

  test "CoffeeScript.eval runs in the global context by default", ->
    global.punctuation = '!'
    code = '''
    global.fhqwhgads = "global superpower#{global.punctuation}"
    '''
    result = CoffeeScript.eval code
    eq result, 'global superpower!'
    eq fhqwhgads, 'global superpower!'

  test "CoffeeScript.eval can run in, and modify, a Script context sandbox", ->
    createContext = vm.Script.createContext ? vm.createContext
    sandbox = createContext()
    sandbox.foo = 'bar'
    code = '''
    global.foo = 'not bar!'
    '''
    result = CoffeeScript.eval code, {sandbox}
    eq result, 'not bar!'
    eq sandbox.foo, 'not bar!'

  test "CoffeeScript.eval can run in, but cannot modify, an ordinary object sandbox", ->
    sandbox = {foo: 'bar'}
    code = '''
    global.foo = 'not bar!'
    '''
    result = CoffeeScript.eval code, {sandbox}
    eq result, 'not bar!'
    eq sandbox.foo, 'bar'

</script>
<script type="text/x-coffeescript" class="test" id="exception_handling">
# Exception Handling
# ------------------

# shared nonce
nonce = {}


# Throw

test "basic exception throwing", ->
  throws (-> throw 'error'), 'error'


# Empty Try/Catch/Finally

test "try can exist alone", ->
  try

test "try/catch with empty try, empty catch", ->
  try
    # nothing
  catch err
    # nothing

test "single-line try/catch with empty try, empty catch", ->
  try catch err

test "try/finally with empty try, empty finally", ->
  try
    # nothing
  finally
    # nothing

test "single-line try/finally with empty try, empty finally", ->
  try finally

test "try/catch/finally with empty try, empty catch, empty finally", ->
  try
  catch err
  finally

test "single-line try/catch/finally with empty try, empty catch, empty finally", ->
  try catch err then finally


# Try/Catch/Finally as an Expression

test "return the result of try when no exception is thrown", ->
  result = try
    nonce
  catch err
    undefined
  finally
    undefined
  eq nonce, result

test "single-line result of try when no exception is thrown", ->
  result = try nonce catch err then undefined
  eq nonce, result

test "return the result of catch when an exception is thrown", ->
  fn = ->
    try
      throw ->
    catch err
      nonce
  doesNotThrow fn
  eq nonce, fn()

test "single-line result of catch when an exception is thrown", ->
  fn = ->
    try throw (->) catch err then nonce
  doesNotThrow fn
  eq nonce, fn()

test "optional catch", ->
  fn = ->
    try throw ->
    nonce
  doesNotThrow fn
  eq nonce, fn()


# Try/Catch/Finally Interaction With Other Constructs

test "try/catch with empty catch as last statement in a function body", ->
  fn = ->
    try nonce
    catch err
  eq nonce, fn()


# Catch leads to broken scoping: #1595

test "try/catch with a reused variable name.", ->
  do ->
    try
      inner = 5
    catch inner
      # nothing
  eq typeof inner, 'undefined'


# Allowed to destructure exceptions: #2580

test "try/catch with destructuring the exception object", ->

  result = try
    missing.object
  catch {message}
    message

  eq message, 'missing is not defined'



test "Try catch finally as implicit arguments", ->
  first = (x) -> x

  foo = no
  try
    first try iamwhoiam() finally foo = yes
  catch e
  eq foo, yes

  bar = no
  try
    first try iamwhoiam() catch e finally
    bar = yes
  catch e
  eq bar, yes

# Catch Should Not Require Param: #2900
test "parameter-less catch clause", ->
  try
    throw new Error 'failed'
  catch
    ok true

  try throw new Error 'failed' catch finally ok true

  ok try throw new Error 'failed' catch then true

</script>
<script type="text/x-coffeescript" class="test" id="formatting">
# Formatting
# ----------

# TODO: maybe this file should be split up into their respective sections:
#   operators -> operators
#   array literals -> array literals
#   string literals -> string literals
#   function invocations -> function invocations

doesNotThrow -> CoffeeScript.compile "a = then b"

test "multiple semicolon-separated statements in parentheticals", ->
  nonce = {}
  eq nonce, (1; 2; nonce)
  eq nonce, (-> return (1; 2; nonce))()

# * Line Continuation
#   * Property Accesss
#   * Operators
#   * Array Literals
#   * Function Invocations
#   * String Literals

# Property Access

test "chained accesses split on period/newline, backwards and forwards", ->
  str = 'abc'
  result = str.
    split('').
    reverse().
    reverse().
    reverse()
  arrayEq ['c','b','a'], result
  arrayEq ['c','b','a'], str.
    split('').
    reverse().
    reverse().
    reverse()
  result = str
    .split('')
    .reverse()
    .reverse()
    .reverse()
  arrayEq ['c','b','a'], result
  arrayEq ['c','b','a'],
    str
    .split('')
    .reverse()
    .reverse()
    .reverse()
  arrayEq ['c','b','a'],
    str.
    split('')
    .reverse().
    reverse()
    .reverse()

# Operators

test "newline suppression for operators", ->
  six =
    1 +
    2 +
    3
  eq 6, six

test "`?.` and `::` should continue lines", ->
  ok not (
    Date
    ::
    ?.foo
  )
  #eq Object::toString, Date?.
  #prototype
  #::
  #?.foo

doesNotThrow -> CoffeeScript.compile """
  oh. yes
  oh?. true
  oh:: return
  """

doesNotThrow -> CoffeeScript.compile """
  a?[b..]
  a?[...b]
  a?[b..c]
  """

# Array Literals

test "indented array literals don't trigger whitespace rewriting", ->
  getArgs = -> arguments
  result = getArgs(
    [[[[[],
                  []],
                [[]]]],
      []])
  eq 1, result.length

# Function Invocations

doesNotThrow -> CoffeeScript.compile """
  obj = then fn 1,
    1: 1
    a:
      b: ->
        fn c,
          d: e
    f: 1
  """

# String Literals

test "indented heredoc", ->
  result = ((_) -> _)(
                """
                abc
                """)
  eq "abc", result

# Chaining - all open calls are closed by property access starting a new line
# * chaining after
#   * indented argument
#   * function block
#   * indented object
#
#   * single line arguments
#   * inline function literal
#   * inline object literal
#
# * chaining inside
#   * implicit object literal

test "chaining after outdent", ->
  id = (x) -> x

  # indented argument
  ff = id parseInt "ff",
    16
  .toString()
  eq '255', ff

  # function block
  str = 'abc'
  zero = parseInt str.replace /\w/, (letter) ->
    0
  .toString()
  eq '0', zero

  # indented object
  a = id id
    a: 1
  .a
  eq 1, a

test "#1495, method call chaining", ->
  str = 'abc'

  result = str.split ''
              .join ', '
  eq 'a, b, c', result

  result = str
  .split ''
  .join ', '
  eq 'a, b, c', result

  eq 'a, b, c', (str
    .split ''
    .join ', '
  )

  eq 'abc',
    'aaabbbccc'.replace /(\w)\1\1/g, '$1$1'
               .replace /([abc])\1/g, '$1'

  # Nested calls
  result = [1..3]
    .slice Math.max 0, 1
    .concat [3]
  arrayEq [2, 3, 3], result

  # Single line function arguments
  result = [1..6]
    .map (x) -> x * x
    .filter (x) -> x % 2 is 0
    .reverse()
  arrayEq [36, 16, 4], result

  # Single line implicit objects
  id = (x) -> x
  result = id a: 1
    .a
  eq 1, result

  # The parens are forced
  result = str.split(''.
    split ''
    .join ''
  ).join ', '
  eq 'a, b, c', result

test "chaining should not wrap spilling ternary", ->
  throws -> CoffeeScript.compile """
    if 0 then 1 else g
      a: 42
    .h()
  """

test "chaining should wrap calls containing spilling ternary", ->
  f = (x) -> h: x
  id = (x) -> x
  result = f if true then 42 else id
      a: 2
  .h
  eq 42, result

test "chaining should work within spilling ternary", ->
  f = (x) -> h: x
  id = (x) -> x
  result = f if false then 1 else id
      a: 3
      .a
  eq 3, result.h

test "method call chaining inside objects", ->
  f = (x) -> c: 42
  result =
    a: f 1
    b: f a: 1
      .c
  eq 42, result.b

test "#4568: refine sameLine implicit object tagging", ->
  condition = yes
  fn = -> yes

  x =
    fn bar: {
      foo: 123
    } if not condition
  eq x, undefined

# Nested blocks caused by paren unwrapping
test "#1492: Nested blocks don't cause double semicolons", ->
  js = CoffeeScript.compile '(0;0)'
  eq -1, js.indexOf ';;'

test "#1195 Ignore trailing semicolons (before newlines or as the last char in a program)", ->
  preNewline = (numSemicolons) ->
    """
    nonce = {}; nonce2 = {}
    f = -> nonce#{Array(numSemicolons+1).join(';')}
    nonce2
    unless f() is nonce then throw new Error('; before linebreak should = newline')
    """
  CoffeeScript.run(preNewline(n), bare: true) for n in [1,2,3]

  lastChar = '-> lastChar;'
  doesNotThrow -> CoffeeScript.compile lastChar, bare: true

test "#1299: Disallow token misnesting", ->
  try
    CoffeeScript.compile '''
      [{
         ]}
    '''
    ok no
  catch e
    eq 'unmatched ]', e.message

test "#2981: Enforce initial indentation", ->
  try
    CoffeeScript.compile '  a\nb-'
    ok no
  catch e
    eq 'missing indentation', e.message

test "'single-line' expression containing multiple lines", ->
  doesNotThrow -> CoffeeScript.compile """
    (a, b) -> if a
      -a
    else if b
    then -b
    else null
  """

test "#1275: allow indentation before closing brackets", ->
  array = [
      1
      2
      3
    ]
  eq array, array
  do ->
  (
    a = 1
   )
  eq 1, a

test "#3199: return multiline implicit object", ->
  y = do ->
    if no then return
      type: 'a'
      msg: 'b'
  eq undefined, y

</script>
<script type="text/x-coffeescript" class="test" id="function_invocation">
# Function Invocation
# -------------------

# * Function Invocation
# * Splats in Function Invocations
# * Implicit Returns
# * Explicit Returns

# shared identity function
id = (_) -> if arguments.length is 1 then _ else [arguments...]

# helper to assert that a string should fail compilation
cantCompile = (code) ->
  throws -> CoffeeScript.compile code

test "basic argument passing", ->

  a = {}
  b = {}
  c = {}
  eq 1, (id 1)
  eq 2, (id 1, 2)[1]
  eq a, (id a)
  eq c, (id a, b, c)[2]


test "passing arguments on separate lines", ->

  a = {}
  b = {}
  c = {}
  ok(id(
    a
    b
    c
  )[1] is b)
  eq(0, id(
    0
    10
  )[0])
  eq(a,id(
    a
  ))
  eq b,
  (id b)


test "optional parens can be used in a nested fashion", ->

  call = (func) -> func()
  add = (a,b) -> a + b
  result = call ->
    inner = call ->
      add 5, 5
  ok result is 10


test "hanging commas and semicolons in argument list", ->

  fn = () -> arguments.length
  eq 2, fn(0,1,)
  eq 3, fn 0, 1,
  2
  eq 2, fn(0, 1;)
  # TODO: this test fails (the string compiles), but should it?
  #throws -> CoffeeScript.compile "fn(0,1,;)"
  throws -> CoffeeScript.compile "fn(0,1,;;)"
  throws -> CoffeeScript.compile "fn(0, 1;,)"
  throws -> CoffeeScript.compile "fn(,0)"
  throws -> CoffeeScript.compile "fn(;0)"


test "function invocation", ->

  func = ->
    return if true
  eq undefined, func()

  result = ("hello".slice) 3
  ok result is 'lo'


test "And even with strange things like this:", ->

  funcs  = [((x) -> x), ((x) -> x * x)]
  result = funcs[1] 5
  ok result is 25


test "More fun with optional parens.", ->

  fn = (arg) -> arg
  ok fn(fn {prop: 101}).prop is 101

  okFunc = (f) -> ok(f())
  okFunc -> true


test "chained function calls", ->
  nonce = {}
  identityWrap = (x) ->
    -> x
  eq nonce, identityWrap(identityWrap(nonce))()()
  eq nonce, (identityWrap identityWrap nonce)()()


test "Multi-blocks with optional parens.", ->

  fn = (arg) -> arg
  result = fn( ->
    fn ->
      "Wrapped"
  )
  ok result()() is 'Wrapped'


test "method calls", ->

  fnId = (fn) -> -> fn.apply this, arguments
  math = {
    add: (a, b) -> a + b
    anonymousAdd: (a, b) -> a + b
    fastAdd: fnId (a, b) -> a + b
  }
  ok math.add(5, 5) is 10
  ok math.anonymousAdd(10, 10) is 20
  ok math.fastAdd(20, 20) is 40


test "Ensure that functions can have a trailing comma in their argument list", ->

  mult = (x, mids..., y) ->
    x *= n for n in mids
    x *= y
  #ok mult(1, 2,) is 2
  #ok mult(1, 2, 3,) is 6
  ok mult(10, (i for i in [1..6])...) is 7200


test "`@` and `this` should both be able to invoke a method", ->
  nonce = {}
  fn          = (arg) -> eq nonce, arg
  fn.withAt   = -> @ nonce
  fn.withThis = -> this nonce
  fn.withAt()
  fn.withThis()


test "Trying an implicit object call with a trailing function.", ->

  a = null
  meth = (arg, obj, func) -> a = [obj.a, arg, func()].join ' '
  meth 'apple', b: 1, a: 13, ->
    'orange'
  ok a is '13 apple orange'


test "Ensure that empty functions don't return mistaken values.", ->

  obj =
    func: (@param, @rest...) ->
  ok obj.func(101, 102, 103, 104) is undefined
  ok obj.param is 101
  ok obj.rest.join(' ') is '102 103 104'


test "Passing multiple functions without paren-wrapping is legal, and should compile.", ->

  sum = (one, two) -> one() + two()
  result = sum ->
    7 + 9
  , ->
    1 + 3
  ok result is 20


test "Implicit call with a trailing if statement as a param.", ->

  func = -> arguments[1]
  result = func 'one', if false then 100 else 13
  ok result is 13


test "Test more function passing:", ->

  sum = (one, two) -> one() + two()

  result = sum( ->
    1 + 2
  , ->
    2 + 1
  )
  ok result is 6

  sum = (a, b) -> a + b
  result = sum(1
  , 2)
  ok result is 3


test "Chained blocks, with proper indentation levels:", ->

  counter =
    results: []
    tick: (func) ->
      @results.push func()
      this
  counter
    .tick ->
      3
    .tick ->
      2
    .tick ->
      1
  arrayEq [3,2,1], counter.results


test "This is a crazy one.", ->

  x = (obj, func) -> func obj
  ident = (x) -> x
  result = x {one: ident 1}, (obj) ->
    inner = ident(obj)
    ident inner
  ok result.one is 1


test "More paren compilation tests:", ->

  reverse = (obj) -> obj.reverse()
  ok reverse([1, 2].concat 3).join(' ') is '3 2 1'


test "Test for inline functions with parentheses and implicit calls.", ->

  combine = (func, num) -> func() * num
  result  = combine (-> 1 + 2), 3
  ok result is 9


test "Test for calls/parens/multiline-chains.", ->

  f = (x) -> x
  result = (f 1).toString()
    .length
  ok result is 1


test "Test implicit calls in functions in parens:", ->

  result = ((val) ->
    [].push val
    val
  )(10)
  ok result is 10


test "Ensure that chained calls with indented implicit object literals below are alright.", ->

  result = null
  obj =
    method: (val)  -> this
    second: (hash) -> result = hash.three
  obj
    .method(
      101
    ).second(
      one:
        two: 2
      three: 3
    )
  eq result, 3


test "Test newline-supressed call chains with nested functions.", ->

  obj  =
    call: -> this
  func = ->
    obj
      .call ->
        one two
      .call ->
        three four
    101
  eq func(), 101


test "Implicit objects with number arguments.", ->

  func = (x, y) -> y
  obj =
    prop: func "a", 1
  ok obj.prop is 1


test "Non-spaced unary and binary operators should cause a function call.", ->

  func = (val) -> val + 1
  ok (func +5) is 6
  ok (func -5) is -4


test "Prefix unary assignment operators are allowed in parenless calls.", ->

  func = (val) -> val + 1
  val = 5
  ok (func --val) is 5

test "#855: execution context for `func arr...` should be `null`", ->
  contextTest = -> eq @, if window? then window else global
  array = []
  contextTest array
  contextTest.apply null, array
  contextTest array...

test "#904: Destructuring function arguments with same-named variables in scope", ->
  a = b = nonce = {}
  fn = ([a,b]) -> {a:a,b:b}
  result = fn([c={},d={}])
  eq c, result.a
  eq d, result.b
  eq nonce, a
  eq nonce, b

test "Simple Destructuring function arguments with same-named variables in scope", ->
  x = 1
  f = ([x]) -> x
  eq f([2]), 2
  eq x, 1

test "caching base value", ->

  obj =
    index: 0
    0: {method: -> this is obj[0]}
  ok obj[obj.index++].method([]...)


test "passing splats to functions", ->
  arrayEq [0..4], id id [0..4]...
  fn = (a, b, c..., d) -> [a, b, c, d]
  range = [0..3]
  [first, second, others, last] = fn range..., 4, [5...8]...
  eq 0, first
  eq 1, second
  arrayEq [2..6], others
  eq 7, last

test "splat variables are local to the function", ->
  outer = "x"
  clobber = (avar, outer...) -> outer
  clobber "foo", "bar"
  eq "x", outer


test "Issue 894: Splatting against constructor-chained functions.", ->

  x = null
  class Foo
    bar: (y) -> x = y
  new Foo().bar([101]...)
  eq x, 101


test "Functions with splats being called with too few arguments.", ->

  pen = null
  method = (first, variable..., penultimate, ultimate) ->
    pen = penultimate
  method 1, 2, 3, 4, 5, 6, 7, 8, 9
  ok pen is 8
  method 1, 2, 3
  ok pen is 2
  method 1, 2
  ok pen is 2


test "splats with super() within classes.", ->

  class Parent
    meth: (args...) ->
      args
  class Child extends Parent
    meth: ->
      nums = [3, 2, 1]
      super nums...
  ok (new Child).meth().join(' ') is '3 2 1'


test "#1011: passing a splat to a method of a number", ->
  eq '1011', 11.toString [2]...
  eq '1011', (31).toString [3]...
  eq '1011', 69.0.toString [4]...
  eq '1011', (131.0).toString [5]...


test "splats and the `new` operator: functions that return `null` should construct their instance", ->
  args = []
  child = new (constructor = -> null) args...
  ok child instanceof constructor

test "splats and the `new` operator: functions that return functions should construct their return value", ->
  args = []
  fn = ->
  child = new (constructor = -> fn) args...
  ok child not instanceof constructor
  eq fn, child

test "implicit return", ->

  eq ok, new ->
    ok
    ### Should `return` implicitly   ###
    ### even with trailing comments. ###


test "implicit returns with multiple branches", ->
  nonce = {}
  fn = ->
    if false
      for a in b
        return c if d
    else
      nonce
  eq nonce, fn()


test "implicit returns with switches", ->
  nonce = {}
  fn = ->
    switch nonce
      when nonce then nonce
      else return undefined
  eq nonce, fn()


test "preserve context when generating closure wrappers for expression conversions", ->
  nonce = {}
  obj =
    property: nonce
    method: ->
      this.result = if false
        10
      else
        "a"
        "b"
        this.property
  eq nonce, obj.method()
  eq nonce, obj.property


test "don't wrap 'pure' statements in a closure", ->
  nonce = {}
  items = [0, 1, 2, 3, nonce, 4, 5]
  fn = (items) ->
    for item in items
      return item if item is nonce
  eq nonce, fn items


test "usage of `new` is careful about where the invocation parens end up", ->
  eq 'object', typeof new try Array
  eq 'object', typeof new do -> ->


test "implicit call against control structures", ->
  result = null
  save   = (obj) -> result = obj

  save switch id false
    when true
      'true'
    when false
      'false'

  eq result, 'false'

  save if id false
    'false'
  else
    'true'

  eq result, 'true'

  save unless id false
    'true'
  else
    'false'

  eq result, 'true'

  save try
    doesnt exist
  catch error
    'caught'

  eq result, 'caught'

  save try doesnt(exist) catch error then 'caught2'

  eq result, 'caught2'


test "#1420: things like `(fn() ->)`; there are no words for this one", ->
  fn = -> (f) -> f()
  nonce = {}
  eq nonce, (fn() -> nonce)

test "#1416: don't omit one 'new' when compiling 'new new'", ->
  nonce = {}
  obj = new new -> -> {prop: nonce}
  eq obj.prop, nonce

test "#1416: don't omit one 'new' when compiling 'new new fn()()'", ->
  nonce = {}
  argNonceA = {}
  argNonceB = {}
  fn = (a) -> (b) -> {a, b, prop: nonce}
  obj = new new fn(argNonceA)(argNonceB)
  eq obj.prop, nonce
  eq obj.a, argNonceA
  eq obj.b, argNonceB

test "#1840: accessing the `prototype` after function invocation should compile", ->
  doesNotThrow -> CoffeeScript.compile 'fn()::prop'

  nonce = {}
  class Test then id: nonce

  dotAccess = -> Test::
  protoAccess = -> Test

  eq dotAccess().id, nonce
  eq protoAccess()::id, nonce

test "#960: improved 'do'", ->

  do (nonExistent = 'one') ->
    eq nonExistent, 'one'

  overridden = 1
  do (overridden = 2) ->
    eq overridden, 2

  two = 2
  do (one = 1, two, three = 3) ->
    eq one, 1
    eq two, 2
    eq three, 3

  ret = do func = (two) ->
    eq two, 2
    func
  eq ret, func

test "#2617: implicit call before unrelated implicit object", ->
  pass = ->
    true

  result = if pass 1
    one: 1
  eq result.one, 1

test "#2292, b: f (z),(x)", ->
  f = (x, y) -> y
  one = 1
  two = 2
  o = b: f (one),(two)
  eq o.b, 2

test "#2297, Different behaviors on interpreting literal", ->
  foo = (x, y) -> y
  bar =
    baz: foo 100, on

  eq bar.baz, on

  qux = (x) -> x
  quux = qux
    corge: foo 100, true

  eq quux.corge, on

  xyzzy =
    e: 1
    f: foo
      a: 1
      b: 2
    ,
      one: 1
      two: 2
      three: 3
    g:
      a: 1
      b: 2
      c: foo 2,
        one: 1
        two: 2
        three: 3
      d: 3
    four: 4
    h: foo one: 1, two: 2, three: three: three: 3,
      2

  eq xyzzy.f.two, 2
  eq xyzzy.g.c.three, 3
  eq xyzzy.four, 4
  eq xyzzy.h, 2

test "#2715, Chained implicit calls", ->
  first  = (x)    -> x
  second = (x, y) -> y

  foo = first first
    one: 1
  eq foo.one, 1

  bar = first second
    one: 1, 2
  eq bar, 2

  baz = first second
    one: 1,
    2
  eq baz, 2

test "Implicit calls and new", ->
  first = (x) -> x
  foo = (@x) ->
  bar = first new foo first 1
  eq bar.x, 1

  third = (x, y, z) -> z
  baz = first new foo new foo third
        one: 1
        two: 2
        1
        three: 3
        2
  eq baz.x.x.three, 3

test "Loose tokens inside of explicit call lists", ->
  first = (x) -> x
  second = (x, y) -> y
  one = 1

  foo = second( one
                2)
  eq foo, 2

  bar = first( first
               one: 1)
  eq bar.one, 1

test "Non-callable literals shouldn't compile", ->
  cantCompile '1(2)'
  cantCompile '1 2'
  cantCompile '/t/(2)'
  cantCompile '/t/ 2'
  cantCompile '///t///(2)'
  cantCompile '///t/// 2'
  cantCompile "''(2)"
  cantCompile "'' 2"
  cantCompile '""(2)'
  cantCompile '"" 2'
  cantCompile '""""""(2)'
  cantCompile '"""""" 2'
  cantCompile '{}(2)'
  cantCompile '{} 2'
  cantCompile '[](2)'
  cantCompile '[] 2'
  cantCompile '[2..9] 2'
  cantCompile '[2..9](2)'
  cantCompile '[1..10][2..9] 2'
  cantCompile '[1..10][2..9](2)'

test 'implicit invocation with implicit object literal', ->
  f = (obj) -> eq 1, obj.a

  f
    a: 1
  obj =
    if f
      a: 2
    else
      a: 1
  eq 2, obj.a

  f
    "a": 1
  obj =
    if f
      "a": 2
    else
      "a": 1
  eq 2, obj.a

  # #3935: Implicit call when the first key of an implicit object has interpolation.
  a = 'a'
  f
    "#{a}": 1
  obj =
    if f
      "#{a}": 2
    else
      "#{a}": 1
  eq 2, obj.a

</script>
<script type="text/x-coffeescript" class="test" id="functions">
# Function Literals
# -----------------

# TODO: add indexing and method invocation tests: (->)[0], (->).call()

# * Function Definition
# * Bound Function Definition
# * Parameter List Features
#   * Splat Parameters
#   * Context (@) Parameters
#   * Parameter Destructuring
#   * Default Parameters

# Function Definition

x = 1
y = {}
y.x = -> 3
ok x is 1
ok typeof(y.x) is 'function'
ok y.x instanceof Function
ok y.x() is 3

# The empty function should not cause a syntax error.
->
() ->

# Multiple nested function declarations mixed with implicit calls should not
# cause a syntax error.
(one) -> (two) -> three four, (five) -> six seven, eight, (nine) ->

# with multiple single-line functions on the same line.
func = (x) -> (x) -> (x) -> x
ok func(1)(2)(3) is 3

# Make incorrect indentation safe.
func = ->
  obj = {
          key: 10
        }
  obj.key - 5
eq func(), 5

# Ensure that functions with the same name don't clash with helper functions.
del = -> 5
ok del() is 5


# Bound Function Definition

obj =
  bound: ->
    (=> this)()
  unbound: ->
    (-> this)()
  nested: ->
    (=>
      (=>
        (=> this)()
      )()
    )()
eq obj, obj.bound()
ok obj isnt obj.unbound()
eq obj, obj.nested()


test "even more fancy bound functions", ->
  obj =
    one: ->
      do =>
        return this.two()
    two: ->
      do =>
        do =>
          do =>
            return this.three
    three: 3

  eq obj.one(), 3


test "self-referencing functions", ->
  changeMe = ->
    changeMe = 2

  changeMe()
  eq changeMe, 2

test "#2009: don't touch `` `this` ``", ->
  nonceA = {}
  nonceB = {}
  fn = null
  (->
    fn = => this is nonceA and `this` is nonceB
  ).call nonceA
  ok fn.call nonceB


# Parameter List Features

test "splats", ->
  arrayEq [0, 1, 2], (((splat...) -> splat) 0, 1, 2)
  arrayEq [2, 3], (((_, _1, splat...) -> splat) 0, 1, 2, 3)
  arrayEq [0, 1], (((splat..., _, _1) -> splat) 0, 1, 2, 3)
  arrayEq [2], (((_, _1, splat..., _2) -> splat) 0, 1, 2, 3)

test "destructured splatted parameters", ->
  arr = [0,1,2]
  splatArray = ([a...]) -> a
  splatArrayRest = ([a...],b...) -> arrayEq(a,b); b
  arrayEq splatArray(arr), arr
  arrayEq splatArrayRest(arr,0,1,2), arr

test "@-parameters: automatically assign an argument's value to a property of the context", ->
  nonce = {}

  ((@prop) ->).call context = {}, nonce
  eq nonce, context.prop

  # allow splats along side the special argument
  ((splat..., @prop) ->).apply context = {}, [0, 0, nonce]
  eq nonce, context.prop

  # allow the argument itself to be a splat
  ((@prop...) ->).call context = {}, 0, nonce, 0
  eq nonce, context.prop[1]

  # the argument should not be able to be referenced normally
  code = '((@prop) -> prop).call {}'
  doesNotThrow -> CoffeeScript.compile code
  throws (-> CoffeeScript.run code), ReferenceError
  code = '((@prop) -> _at_prop).call {}'
  doesNotThrow -> CoffeeScript.compile code
  throws (-> CoffeeScript.run code), ReferenceError

test "@-parameters and splats with constructors", ->
  a = {}
  b = {}
  class Klass
    constructor: (@first, splat..., @last) ->

  obj = new Klass a, 0, 0, b
  eq a, obj.first
  eq b, obj.last

test "destructuring in function definition", ->
  (([{a: [b], c}]...) ->
    eq 1, b
    eq 2, c
  ) {a: [1], c: 2}

  context = {}
  (([{a: [b, c = 2], @d, e = 4}]...) ->
    eq 1, b
    eq 2, c
    eq @d, 3
    eq context.d, 3
    eq e, 4
  ).call context, {a: [1], d: 3}

  (({a: aa = 1, b: bb = 2}) ->
    eq 5, aa
    eq 2, bb
  ) {a: 5}

  ajax = (url, {
    async = true,
    beforeSend = (->),
    cache = true,
    method = 'get',
    data = {}
  }) ->
    {url, async, beforeSend, cache, method, data}

  fn = ->
  deepEqual ajax('/home', beforeSend: fn, cache: null, method: 'post'), {
    url: '/home', async: true, beforeSend: fn, cache: true, method: 'post', data: {}
  }

test "#4005: `([a = {}]..., b) ->` weirdness", ->
  fn = ([a = {}]..., b) -> [a, b]
  deepEqual fn(5), [{}, 5]

test "default values", ->
  nonceA = {}
  nonceB = {}
  a = (_,_1,arg=nonceA) -> arg
  eq nonceA, a()
  eq nonceA, a(0)
  eq nonceB, a(0,0,nonceB)
  eq nonceA, a(0,0,undefined)
  eq nonceA, a(0,0,null)
  eq false , a(0,0,false)
  eq nonceB, a(undefined,undefined,nonceB,undefined)
  b = (_,arg=nonceA,_1,_2) -> arg
  eq nonceA, b()
  eq nonceA, b(0)
  eq nonceB, b(0,nonceB)
  eq nonceA, b(0,undefined)
  eq nonceA, b(0,null)
  eq false , b(0,false)
  eq nonceB, b(undefined,nonceB,undefined)
  c = (arg=nonceA,_,_1) -> arg
  eq nonceA, c()
  eq      0, c(0)
  eq nonceB, c(nonceB)
  eq nonceA, c(undefined)
  eq nonceA, c(null)
  eq false , c(false)
  eq nonceB, c(nonceB,undefined,undefined)

test "default values with @-parameters", ->
  a = {}
  b = {}
  obj = f: (q = a, @p = b) -> q
  eq a, obj.f()
  eq b, obj.p

test "default values with splatted arguments", ->
  withSplats = (a = 2, b..., c = 3, d = 5) -> a * (b.length + 1) * c * d
  eq 30, withSplats()
  eq 15, withSplats(1)
  eq  5, withSplats(1,1)
  eq  1, withSplats(1,1,1)
  eq  2, withSplats(1,1,1,1)

test "#156: parameter lists with expansion", ->
  expandArguments = (first, ..., lastButOne, last) ->
    eq 1, first
    eq 4, lastButOne
    last
  eq 5, expandArguments 1, 2, 3, 4, 5

  throws (-> CoffeeScript.compile "(..., a, b...) ->"), null, "prohibit expansion and a splat"
  throws (-> CoffeeScript.compile "(...) ->"),          null, "prohibit lone expansion"

test "#156: parameter lists with expansion in array destructuring", ->
  expandArray = (..., [..., last]) ->
    last
  eq 3, expandArray 1, 2, 3, [1, 2, 3]

test "#3502: variable definitions and expansion", ->
  a = b = 0
  f = (a, ..., b) -> [a, b]
  arrayEq [1, 5], f 1, 2, 3, 4, 5
  eq 0, a
  eq 0, b

test "variable definitions and splat", ->
  a = b = 0
  f = (a, middle..., b) -> [a, middle, b]
  arrayEq [1, [2, 3, 4], 5], f 1, 2, 3, 4, 5
  eq 0, a
  eq 0, b

test "default values with function calls", ->
  doesNotThrow -> CoffeeScript.compile "(x = f()) ->"

test "arguments vs parameters", ->
  doesNotThrow -> CoffeeScript.compile "f(x) ->"
  f = (g) -> g()
  eq 5, f (x) -> 5

test "reserved keyword as parameters", ->
  f = (_case, @case) -> [_case, @case]
  [a, b] = f(1, 2)
  eq 1, a
  eq 2, b

  f = (@case, _case...) -> [@case, _case...]
  [a, b, c] = f(1, 2, 3)
  eq 1, a
  eq 2, b
  eq 3, c

test "reserved keyword at-splat", ->
  f = (@case...) -> @case
  [a, b] = f(1, 2)
  eq 1, a
  eq 2, b

test "#1574: Destructuring and a parameter named _arg", ->
  f = ({a, b}, _arg, _arg1) -> [a, b, _arg, _arg1]
  arrayEq [1, 2, 3, 4], f a: 1, b: 2, 3, 4

test "#1844: bound functions in nested comprehensions causing empty var statements", ->
  a = ((=>) for a in [0] for b in [0])
  eq 1, a.length

test "#1859: inline function bodies shouldn't modify prior postfix ifs", ->
  list = [1, 2, 3]
  ok true if list.some (x) -> x is 2

test "#2258: allow whitespace-style parameter lists in function definitions", ->
  func = (
    a, b, c
  ) -> c
  eq func(1, 2, 3), 3

  func = (
    a
    b
    c
  ) -> b
  eq func(1, 2, 3), 2

test "#2621: fancy destructuring in parameter lists", ->
  func = ({ prop1: { key1 }, prop2: { key2, key3: [a, b, c] } }) ->
    eq(key2, 'key2')
    eq(a, 'a')

  func({prop1: {key1: 'key1'}, prop2: {key2: 'key2', key3: ['a', 'b', 'c']}})

test "#1435 Indented property access", ->
  rec = -> rec: rec

  eq 1, do ->
    rec()
      .rec ->
        rec()
          .rec ->
            rec.rec()
          .rec()
    1

test "#1038 Optimize trailing return statements", ->
  compile = (code) -> CoffeeScript.compile(code, bare: yes).trim().replace(/\s+/g, " ")

  eq "(function() {});",                 compile("->")
  eq "(function() {});",                 compile("-> return")
  eq "(function() { return void 0; });", compile("-> undefined")
  eq "(function() { return void 0; });", compile("-> return undefined")
  eq "(function() { foo(); });",         compile("""
                                                 ->
                                                   foo()
                                                   return
                                                 """)

</script>
<script type="text/x-coffeescript" class="test" id="generators">
# Generators
# -----------------
#
# * Generator Definition

test "most basic generator support", ->
  ok -> yield

test "empty generator", ->
  x = do -> yield return

  y = x.next()
  ok y.value is undefined and y.done is true

test "generator iteration", ->
  x = do ->
    yield 0
    yield
    yield 2
    3

  y = x.next()
  ok y.value is 0 and y.done is false

  y = x.next()
  ok y.value is undefined and y.done is false

  y = x.next()
  ok y.value is 2 and y.done is false

  y = x.next()
  ok y.value is 3 and y.done is true

test "last line yields are returned", ->
  x = do ->
    yield 3
  y = x.next()
  ok y.value is 3 and y.done is false

  y = x.next 42
  ok y.value is 42 and y.done is true

test "yield return can be used anywhere in the function body", ->
  x = do ->
    if 2 is yield 1
      yield return 42
    throw new Error "this code shouldn't be reachable"

  y = x.next()
  ok y.value is 1 and y.done is false

  y = x.next 2
  ok y.value is 42 and y.done is true

test "bound generator", ->
  obj =
    bound: ->
      do =>
        yield this
    unbound: ->
      do ->
        yield this
    nested: ->
      do =>
        yield do =>
          yield do =>
            yield this

  eq obj, obj.bound().next().value
  ok obj isnt obj.unbound().next().value
  eq obj, obj.nested().next().value.next().value.next().value

test "`yield from` support", ->
  x = do ->
    yield from do ->
      yield i for i in [3..4]

  y = x.next()
  ok y.value is 3 and y.done is false

  y = x.next 1
  ok y.value is 4 and y.done is false

  y = x.next 2
  arrayEq y.value, [1, 2]
  ok y.done is true

test "error if `yield from` occurs outside of a function", ->
  throws -> CoffeeScript.compile 'yield from 1'

test "`yield from` at the end of a function errors", ->
  throws -> CoffeeScript.compile 'x = -> x = 1; yield from'

test "yield in if statements", ->
  x = do -> if 1 is yield 2 then 3 else 4

  y = x.next()
  ok y.value is 2 and y.done is false

  y = x.next 1
  ok y.value is 3 and y.done is true

test "yielding if statements", ->
  x = do -> yield if true then 3 else 4

  y = x.next()
  ok y.value is 3 and y.done is false

  y = x.next 42
  ok y.value is 42 and y.done is true

test "yield in for loop expressions", ->
  x = do ->
    y = for i in [1..3]
      yield i * 2

  z = x.next()
  ok z.value is 2 and z.done is false

  z = x.next 10
  ok z.value is 4 and z.done is false

  z = x.next 20
  ok z.value is 6 and z.done is false

  z = x.next 30
  arrayEq z.value, [10, 20, 30]
  ok z.done is true

test "yield in switch expressions", ->
  x = do ->
    y = switch yield 1
      when 2 then yield 1337
      else 1336

  z = x.next()
  ok z.value is 1 and z.done is false

  z = x.next 2
  ok z.value is 1337 and z.done is false

  z = x.next 3
  ok z.value is 3 and z.done is true

test "yielding switch expressions", ->
  x = do ->
    yield switch 1337
      when 1337 then 1338
      else 1336

  y = x.next()
  ok y.value is 1338 and y.done is false

  y = x.next 42
  ok y.value is 42 and y.done is true

test "yield in try expressions", ->
  x = do ->
    try yield 1 catch

  y = x.next()
  ok y.value is 1 and y.done is false

  y = x.next 42
  ok y.value is 42 and y.done is true

test "yielding try expressions", ->
  x = do ->
    yield try 1

  y = x.next()
  ok y.value is 1 and y.done is false

  y = x.next 42
  ok y.value is 42 and y.done is true

test "`yield` can be thrown", ->
  x = do ->
    throw yield null
  x.next()
  throws -> x.next new Error "boom"

test "`throw` can be yielded", ->
  x = do ->
    yield throw new Error "boom"
  throws -> x.next()

test "symbolic operators has precedence over the `yield`", ->
  symbolic   = '+ - * / << >> & | || && ** ^ // or and'.split ' '
  compound   = ("#{op}=" for op in symbolic)
  relations  = '< > == != <= >= is isnt'.split ' '

  operators  = [symbolic..., '=', compound..., relations...]

  collect = (gen) -> ref.value until (ref = gen.next()).done

  values = [0, 1, 2, 3]
  for op in operators
    expression = "i #{op} 2"

    yielded = CoffeeScript.eval "(arr) ->  yield #{expression} for i in arr"
    mapped  = CoffeeScript.eval "(arr) ->       (#{expression} for i in arr)"

    arrayEq mapped(values), collect yielded values

test "yield handles 'this' correctly", ->
  x = ->
    yield switch
      when true then yield => this
    array = for item in [1]
      yield => this
    yield array
    yield if true then yield => this
    yield try throw yield => this
    throw yield => this

  y = x.call [1, 2, 3]

  z = y.next()
  arrayEq z.value(), [1, 2, 3]
  ok z.done is false

  z = y.next 123
  ok z.value is 123 and z.done is false

  z = y.next()
  arrayEq z.value(), [1, 2, 3]
  ok z.done is false

  z = y.next 42
  arrayEq z.value, [42]
  ok z.done is false

  z = y.next()
  arrayEq z.value(), [1, 2, 3]
  ok z.done is false

  z = y.next 456
  ok z.value is 456 and z.done is false

  z = y.next()
  arrayEq z.value(), [1, 2, 3]
  ok z.done is false

  z = y.next new Error "ignore me"
  ok z.value is undefined and z.done is false

  z = y.next()
  arrayEq z.value(), [1, 2, 3]
  ok z.done is false

  throws -> y.next new Error "boom"

test "for-from loops over generators", ->
  array1 = [50, 30, 70, 20]
  gen = -> yield from array1

  array2 = []
  array3 = []
  array4 = []

  iterator = gen()
  for x from iterator
    array2.push(x)
    break if x is 30

  for x from iterator
    array3.push(x)

  for x from iterator
    array4.push(x)

  arrayEq array2, [50, 30]
  # Different JS engines have different opinions on the value of array3:
  # https://github.com/jashkenas/coffeescript/pull/4306#issuecomment-257066877
  # As a temporary measure, either result is accepted.
  ok array3.length is 0 or array3.join(',') is '70,20'
  arrayEq array4, []

test "for-from comprehensions over generators", ->
  gen = ->
    yield from [30, 41, 51, 60]

  iterator = gen()
  array1 = (x for x from iterator when x %% 2 is 1)
  array2 = (x for x from iterator)

  ok array1.join(' ') is '41 51'
  ok array2.length is 0

test "from as an iterable variable name in a for loop declaration", ->
  from = [1, 2, 3]
  out = []
  for i from from
    out.push i
  arrayEq from, out

test "from as an iterator variable name in a for loop declaration", ->
  a = [1, 2, 3]
  b = []
  for from from a
    b.push from
  arrayEq a, b

test "from as a destructured object variable name in a for loop declaration", ->
  a = [
      from: 1
      to: 2
    ,
      from: 3
      to: 4
  ]
  b = []
  for {from, to} in a
    b.push from
  arrayEq b, [1, 3]

  c = []
  for {to, from} in a
    c.push from
  arrayEq c, [1, 3]

test "from as a destructured, aliased object variable name in a for loop declaration", ->
  a = [
      b: 1
      c: 2
    ,
      b: 3
      c: 4
  ]
  out = []

  for {b: from} in a
    out.push from
  arrayEq out, [1, 3]

test "from as a destructured array variable name in a for loop declaration", ->
  a = [
    [1, 2]
    [3, 4]
  ]
  b = []
  for [from, to] from a
    b.push from
  arrayEq b, [1, 3]

</script>
<script type="text/x-coffeescript" class="test" id="helpers">
# Helpers
# -------

# pull the helpers from `CoffeeScript.helpers` into local variables
{starts, ends, repeat, compact, count, merge, extend, flatten, del, baseFileName} = CoffeeScript.helpers


# `starts`

test "the `starts` helper tests if a string starts with another string", ->
  ok     starts('01234', '012')
  ok not starts('01234', '123')

test "the `starts` helper can take an optional offset", ->
  ok     starts('01234', '34', 3)
  ok not starts('01234', '01', 1)


# `ends`

test "the `ends` helper tests if a string ends with another string", ->
  ok     ends('01234', '234')
  ok not ends('01234', '012')

test "the `ends` helper can take an optional offset", ->
  ok     ends('01234', '012', 2)
  ok not ends('01234', '234', 6)


# `repeat`

test "the `repeat` helper concatenates a given number of times", ->
  eq 'asdasdasd', repeat('asd', 3)

test "`repeat`ing a string 0 times always returns the empty string", ->
  eq '', repeat('whatever', 0)


# `compact`

test "the `compact` helper removes falsey values from an array, preserves truthy ones", ->
  allValues = [1, 0, false, obj={}, [], '', ' ', -1, null, undefined, true]
  truthyValues = [1, obj, [], ' ', -1, true]
  arrayEq truthyValues, compact(allValues)


# `count`

test "the `count` helper counts the number of occurrences of a string in another string", ->
  eq 1/0, count('abc', '')
  eq 0, count('abc', 'z')
  eq 1, count('abc', 'a')
  eq 1, count('abc', 'b')
  eq 2, count('abcdc', 'c')
  eq 2, count('abcdabcd','abc')


# `merge`

test "the `merge` helper makes a new object with all properties of the objects given as its arguments", ->
  ary = [0, 1, 2, 3, 4]
  obj = {}
  merged = merge obj, ary
  ok merged isnt obj
  ok merged isnt ary
  for own key, val of ary
    eq val, merged[key]


# `extend`

test "the `extend` helper performs a shallow copy", ->
  ary = [0, 1, 2, 3]
  obj = {}
  # should return the object being extended
  eq obj, extend(obj, ary)
  # should copy the other object's properties as well (obviously)
  eq 2, obj[2]


# `flatten`

test "the `flatten` helper flattens an array", ->
  success = yes
  (success and= typeof n is 'number') for n in flatten [0, [[[1]], 2], 3, [4]]
  ok success


# `del`

test "the `del` helper deletes a property from an object and returns the deleted value", ->
  obj = [0, 1, 2]
  eq 1, del(obj, 1)
  ok 1 not of obj


# `baseFileName`

test "the `baseFileName` helper returns the file name to write to", ->
  ext = '.js'
  sourceToCompiled =
    '.coffee': ext
    'a.coffee': 'a' + ext
    'b.coffee': 'b' + ext
    'coffee.coffee': 'coffee' + ext

    '.litcoffee': ext
    'a.litcoffee': 'a' + ext
    'b.litcoffee': 'b' + ext
    'coffee.litcoffee': 'coffee' + ext

    '.lit': ext
    'a.lit': 'a' + ext
    'b.lit': 'b' + ext
    'coffee.lit': 'coffee' + ext

    '.coffee.md': ext
    'a.coffee.md': 'a' + ext
    'b.coffee.md': 'b' + ext
    'coffee.coffee.md': 'coffee' + ext

  for sourceFileName, expectedFileName of sourceToCompiled
    name = baseFileName sourceFileName, yes
    filename = name + ext
    eq filename, expectedFileName

</script>
<script type="text/x-coffeescript" class="test" id="importing">
# Importing
# ---------

unless window? or testingBrowser?
  test "coffeescript modules can be imported and executed", ->

    magicKey = __filename
    magicValue = 0xFFFF

    if global[magicKey]?
      if exports?
        local = magicValue
        exports.method = -> local
    else
      global[magicKey] = {}
      if require?.extensions?
        ok require(__filename).method() is magicValue
      delete global[magicKey]

  test "javascript modules can be imported", ->
    magicVal = 1
    for module in 'import.js import2 .import2 import.extension.js import.unknownextension .coffee .coffee.md'.split ' '
      ok require("./importing/#{module}").value?() is magicVal, module

  test "coffeescript modules can be imported", ->
    magicVal = 2
    for module in '.import.coffee import.coffee import.extension.coffee'.split ' '
      ok require("./importing/#{module}").value?() is magicVal, module

  test "literate coffeescript modules can be imported", ->
    magicVal = 3
    # Leading space intentional to check for index.coffee.md
    for module in ' .import.coffee.md import.coffee.md import.litcoffee import.extension.coffee.md'.split ' '
      ok require("./importing/#{module}").value?() is magicVal, module

</script>
<script type="text/x-coffeescript" class="test" id="interpolation">
# Interpolation
# -------------

# * String Interpolation
# * Regular Expression Interpolation

# String Interpolation

# TODO: refactor string interpolation tests

eq 'multiline nested "interpolations" work', """multiline #{
  "nested #{
    ok true
    "\"interpolations\""
  }"
} work"""

# Issue #923: Tricky interpolation.
eq "#{ "{" }", "{"
eq "#{ '#{}}' } }", '#{}} }'
eq "#{"'#{ ({a: "b#{1}"}['a']) }'"}", "'b1'"

# Issue #1150: String interpolation regression
eq "#{'"/'}",                '"/'
eq "#{"/'"}",                "/'"
eq "#{/'"/}",                '/\'"/'
eq "#{"'/" + '/"' + /"'/}",  '\'//"/"\'/'
eq "#{"'/"}#{'/"'}#{/"'/}",  '\'//"/"\'/'
eq "#{6 / 2}",               '3'
eq "#{6 / 2}#{6 / 2}",       '33' # parsed as division
eq "#{6 + /2}#{6/ + 2}",     '6/2}#{6/2' # parsed as a regex
eq "#{6/2}
    #{6/2}",                 '3 3' # newline cannot be part of a regex, so it's division
eq "#{/// "'/'"/" ///}",     '/"\'\\/\'"\\/"/' # heregex, stuffed with spicy characters
eq "#{/\\'/}",               "/\\\\'/"

# Issue #2321: Regex/division conflict in interpolation
eq "#{4/2}/", '2/'
curWidth = 4
eq "<i style='left:#{ curWidth/2 }%;'></i>",   "<i style='left:2%;'></i>"
throws -> CoffeeScript.compile '''
   "<i style='left:#{ curWidth /2 }%;'></i>"'''
#                 valid regex--^^^^^^^^^^^ ^--unclosed string
eq "<i style='left:#{ curWidth/2 }%;'></i>",   "<i style='left:2%;'></i>"
eq "<i style='left:#{ curWidth/ 2 }%;'></i>",  "<i style='left:2%;'></i>"
eq "<i style='left:#{ curWidth / 2 }%;'></i>", "<i style='left:2%;'></i>"

hello = 'Hello'
world = 'World'
ok '#{hello} #{world}!' is '#{hello} #{world}!'
ok "#{hello} #{world}!" is 'Hello World!'
ok "[#{hello}#{world}]" is '[HelloWorld]'
ok "#{hello}##{world}" is 'Hello#World'
ok "Hello #{ 1 + 2 } World" is 'Hello 3 World'
ok "#{hello} #{ 1 + 2 } #{world}" is "Hello 3 World"
ok 1 + "#{2}px" is '12px'
ok isNaN "a#{2}" * 2
ok "#{2}" is '2'
ok "#{2}#{2}" is '22'

[s, t, r, i, n, g] = ['s', 't', 'r', 'i', 'n', 'g']
ok "#{s}#{t}#{r}#{i}#{n}#{g}" is 'string'
ok "\#{s}\#{t}\#{r}\#{i}\#{n}\#{g}" is '#{s}#{t}#{r}#{i}#{n}#{g}'
ok "\#{string}" is '#{string}'

ok "\#{Escaping} first" is '#{Escaping} first'
ok "Escaping \#{in} middle" is 'Escaping #{in} middle'
ok "Escaping \#{last}" is 'Escaping #{last}'

ok "##" is '##'
ok "#{}" is ''
ok "#{}A#{} #{} #{}B#{}" is 'A  B'
ok "\\\#{}" is '\\#{}'

ok "I won ##{20} last night." is 'I won #20 last night.'
ok "I won ##{'#20'} last night." is 'I won ##20 last night.'

ok "#{hello + world}" is 'HelloWorld'
ok "#{hello + ' ' + world + '!'}" is 'Hello World!'

list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ok "values: #{list.join(', ')}, length: #{list.length}." is 'values: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, length: 10.'
ok "values: #{list.join ' '}" is 'values: 0 1 2 3 4 5 6 7 8 9'

obj = {
  name: 'Joe'
  hi: -> "Hello #{@name}."
  cya: -> "Hello #{@name}.".replace('Hello','Goodbye')
}
ok obj.hi() is "Hello Joe."
ok obj.cya() is "Goodbye Joe."

ok "With #{"quotes"}" is 'With quotes'
ok 'With #{"quotes"}' is 'With #{"quotes"}'

ok "Where is #{obj["name"] + '?'}" is 'Where is Joe?'

ok "Where is #{"the nested #{obj["name"]}"}?" is 'Where is the nested Joe?'
ok "Hello #{world ? "#{hello}"}" is 'Hello World'

ok "Hello #{"#{"#{obj["name"]}" + '!'}"}" is 'Hello Joe!'

a = """
    Hello #{ "Joe" }
    """
ok a is "Hello Joe"

a = 1
b = 2
c = 3
ok "#{a}#{b}#{c}" is '123'

result = null
stash = (str) -> result = str
stash "a #{ ('aa').replace /a/g, 'b' } c"
ok result is 'a bb c'

foo = "hello"
ok "#{foo.replace("\"", "")}" is 'hello'

val = 10
a = """
    basic heredoc #{val}
    on two lines
    """
b = '''
    basic heredoc #{val}
    on two lines
    '''
ok a is "basic heredoc 10\non two lines"
ok b is "basic heredoc \#{val}\non two lines"

eq 'multiline nested "interpolations" work', """multiline #{
  "nested #{(->
    ok yes
    "\"interpolations\""
  )()}"
} work"""

eq 'function(){}', "#{->}".replace /\s/g, ''
ok /^a[\s\S]+b$/.test "a#{=>}b"
ok /^a[\s\S]+b$/.test "a#{ (x) -> x ** 2 }b"

# Regular Expression Interpolation

# TODO: improve heregex interpolation tests

test "heregex interpolation", ->
  eq /\\#{}\\"/ + '', ///
   #{
     "#{ '\\' }" # normal comment
   }
   # regex comment
   \#{}
   \\ "
  /// + ''

</script>
<script type="text/x-coffeescript" class="test" id="javascript_literals">
# JavaScript Literals
# -------------------

test "inline JavaScript is evaluated", ->
  eq '\\`', `
    // Inline JS
    "\\\\\`"
  `

test "escaped backticks are output correctly", ->
  `var a = \`2 + 2 = ${4}\``
  eq a, '2 + 2 = 4'

test "backslashes before a newline don’t break JavaScript blocks", ->
  `var a = \`To be, or not\\
  to be.\``
  eq a, '''
  To be, or not\\
    to be.'''

test "block inline JavaScript is evaluated", ->
  ```
  var a = 1;
  var b = 2;
  ```
  c = 3
  ```var d = 4;```
  eq a + b + c + d, 10

test "block inline JavaScript containing backticks", ->
  ```
  // This is a comment with `backticks`
  var a = 42;
  var b = `foo ${'bar'}`;
  var c = 3;
  var d = 'foo`bar`';
  ```
  eq a + c, 45
  eq b, 'foo bar'
  eq d, 'foo`bar`'

test "block JavaScript can end with an escaped backtick character", ->
  ```var a = \`hello\````
  ```
  var b = \`world${'!'}\````
  eq a, 'hello'
  eq b, 'world!'

test "JavaScript block only escapes backslashes followed by backticks", ->
  eq `'\\\n'`, '\\\n'

test "escaped JavaScript blocks speed round", ->
  # The following has escaped backslashes because they’re required in strings, but the intent is this:
  # `hello`                                       → hello;
  # `\`hello\``                                   → `hello`;
  # `\`Escaping backticks in JS: \\\`hello\\\`\`` → `Escaping backticks in JS: \`hello\``;
  # `Single backslash: \ `                        → Single backslash: \ ;
  # `Double backslash: \\ `                       → Double backslash: \\ ;
  # `Single backslash at EOS: \\`                 → Single backslash at EOS: \;
  # `Double backslash at EOS: \\\\`               → Double backslash at EOS: \\;
  for [input, output] in [
    ['`hello`',                                               'hello;']
    ['`\\`hello\\``',                                         '`hello`;']
    ['`\\`Escaping backticks in JS: \\\\\\`hello\\\\\\`\\``', '`Escaping backticks in JS: \\`hello\\``;']
    ['`Single backslash: \\ `',                               'Single backslash: \\ ;']
    ['`Double backslash: \\\\ `',                             'Double backslash: \\\\ ;']
    ['`Single backslash at EOS: \\\\`',                       'Single backslash at EOS: \\;']
    ['`Double backslash at EOS: \\\\\\\\`',                   'Double backslash at EOS: \\\\;']
  ]
    eq CoffeeScript.compile(input, bare: yes), "#{output}\n\n"

</script>
<script type="text/x-literate-coffeescript" class="test" id="literate">
Literate CoffeeScript Test
--------------------------

comment comment

    test "basic literate CoffeeScript parsing", ->
      ok yes
      
now with a...
  
    test "broken up indentation", ->
    
... broken up ...

      do ->
      
... nested block.

        ok yes

Code must be separated from text by a blank line.

    test "code blocks must be preceded by a blank line", ->

The next line is part of the text and will not be executed.
      fail()

      ok yes        
        
Code in `backticks is not parsed` and...

    test "comments in indented blocks work", ->
      do ->
        do ->
          # Regular comment.
          
          ###
            Block comment.
          ###
          
          ok yes
          
Regular [Markdown](http://example.com/markdown) features, like links 
and unordered lists, are fine:

  * I 
  
  * Am
  
  * A
  
  * List

Tabs work too:

				test "tabbed code", ->
					ok yes

</script>
<script type="text/x-coffeescript" class="test" id="location">
testScript = '''
if true
  x = 6
  console.log "A console #{x + 7} log"

foo = "bar"
z = /// ^ (a#{foo}) ///

x = () ->
    try
        console.log "foo"
    catch err
        # Rewriter will generate explicit indentation here.

    return null
'''

test "Verify location of generated tokens", ->
  tokens = CoffeeScript.tokens "a = 79"

  eq tokens.length, 4
  [aToken, equalsToken, numberToken] = tokens

  eq aToken[2].first_line, 0
  eq aToken[2].first_column, 0
  eq aToken[2].last_line, 0
  eq aToken[2].last_column, 0

  eq equalsToken[2].first_line, 0
  eq equalsToken[2].first_column, 2
  eq equalsToken[2].last_line, 0
  eq equalsToken[2].last_column, 2

  eq numberToken[2].first_line, 0
  eq numberToken[2].first_column, 4
  eq numberToken[2].last_line, 0
  eq numberToken[2].last_column, 5

test "Verify location of generated tokens (with indented first line)", ->
  tokens = CoffeeScript.tokens "  a = 83"

  eq tokens.length, 4
  [aToken, equalsToken, numberToken] = tokens

  eq aToken[2].first_line, 0
  eq aToken[2].first_column, 2
  eq aToken[2].last_line, 0
  eq aToken[2].last_column, 2

  eq equalsToken[2].first_line, 0
  eq equalsToken[2].first_column, 4
  eq equalsToken[2].last_line, 0
  eq equalsToken[2].last_column, 4

  eq numberToken[2].first_line, 0
  eq numberToken[2].first_column, 6
  eq numberToken[2].last_line, 0
  eq numberToken[2].last_column, 7

getMatchingTokens = (str, wantedTokens...) ->
  tokens = CoffeeScript.tokens str
  matchingTokens = []
  i = 0
  for token in tokens
    if token[1].replace(/^'|'$/g, '"') is wantedTokens[i]
      i++
      matchingTokens.push token
  eq wantedTokens.length, matchingTokens.length
  matchingTokens

test 'Verify locations in string interpolation (in "string")', ->
  [a, b, c] = getMatchingTokens '"a#{b}c"', '"a"', 'b', '"c"'

  eq a[2].first_line, 0
  eq a[2].first_column, 0
  eq a[2].last_line, 0
  eq a[2].last_column, 1

  eq b[2].first_line, 0
  eq b[2].first_column, 4
  eq b[2].last_line, 0
  eq b[2].last_column, 4

  eq c[2].first_line, 0
  eq c[2].first_column, 6
  eq c[2].last_line, 0
  eq c[2].last_column, 7

test 'Verify locations in string interpolation (in "string", multiple interpolation)', ->
  [a, b, c] = getMatchingTokens '"#{a}b#{c}"', 'a', '"b"', 'c'

  eq a[2].first_line, 0
  eq a[2].first_column, 3
  eq a[2].last_line, 0
  eq a[2].last_column, 3

  eq b[2].first_line, 0
  eq b[2].first_column, 5
  eq b[2].last_line, 0
  eq b[2].last_column, 5

  eq c[2].first_line, 0
  eq c[2].first_column, 8
  eq c[2].last_line, 0
  eq c[2].last_column, 8

test 'Verify locations in string interpolation (in "string", multiple interpolation and line breaks)', ->
  [a, b, c] = getMatchingTokens '"#{a}\nb\n#{c}"', 'a', '" b "', 'c'

  eq a[2].first_line, 0
  eq a[2].first_column, 3
  eq a[2].last_line, 0
  eq a[2].last_column, 3

  eq b[2].first_line, 0
  eq b[2].first_column, 5
  eq b[2].last_line, 1
  eq b[2].last_column, 1

  eq c[2].first_line, 2
  eq c[2].first_column, 2
  eq c[2].last_line, 2
  eq c[2].last_column, 2

test 'Verify locations in string interpolation (in "string", multiple interpolation and starting with line breaks)', ->
  [a, b, c] = getMatchingTokens '"\n#{a}\nb\n#{c}"', 'a', '" b "', 'c'

  eq a[2].first_line, 1
  eq a[2].first_column, 2
  eq a[2].last_line, 1
  eq a[2].last_column, 2

  eq b[2].first_line, 1
  eq b[2].first_column, 4
  eq b[2].last_line, 2
  eq b[2].last_column, 1

  eq c[2].first_line, 3
  eq c[2].first_column, 2
  eq c[2].last_line, 3
  eq c[2].last_column, 2

test 'Verify locations in string interpolation (in "string", multiple interpolation and starting with line breaks)', ->
  [a, b, c] = getMatchingTokens '"\n\n#{a}\n\nb\n\n#{c}"', 'a', '" b "', 'c'

  eq a[2].first_line, 2
  eq a[2].first_column, 2
  eq a[2].last_line, 2
  eq a[2].last_column, 2

  eq b[2].first_line, 2
  eq b[2].first_column, 4
  eq b[2].last_line, 5
  eq b[2].last_column, 0

  eq c[2].first_line, 6
  eq c[2].first_column, 2
  eq c[2].last_line, 6
  eq c[2].last_column, 2

test 'Verify locations in string interpolation (in "string", multiple interpolation and starting with line breaks)', ->
  [a, b, c] = getMatchingTokens '"\n\n\n#{a}\n\n\nb\n\n\n#{c}"', 'a', '" b "', 'c'

  eq a[2].first_line, 3
  eq a[2].first_column, 2
  eq a[2].last_line, 3
  eq a[2].last_column, 2

  eq b[2].first_line, 3
  eq b[2].first_column, 4
  eq b[2].last_line, 8
  eq b[2].last_column, 0

  eq c[2].first_line, 9
  eq c[2].first_column, 2
  eq c[2].last_line, 9
  eq c[2].last_column, 2

test 'Verify locations in string interpolation (in """string""", line breaks)', ->
  [a, b, c] = getMatchingTokens '"""a\n#{b}\nc"""', '"a\\n"', 'b', '"\\nc"'

  eq a[2].first_line, 0
  eq a[2].first_column, 0
  eq a[2].last_line, 0
  eq a[2].last_column, 4

  eq b[2].first_line, 1
  eq b[2].first_column, 2
  eq b[2].last_line, 1
  eq b[2].last_column, 2

  eq c[2].first_line, 1
  eq c[2].first_column, 4
  eq c[2].last_line, 2
  eq c[2].last_column, 3

test 'Verify locations in string interpolation (in """string""", starting with a line break)', ->
  [b, c] = getMatchingTokens '"""\n#{b}\nc"""', 'b', '"\\nc"'

  eq b[2].first_line, 1
  eq b[2].first_column, 2
  eq b[2].last_line, 1
  eq b[2].last_column, 2

  eq c[2].first_line, 1
  eq c[2].first_column, 4
  eq c[2].last_line, 2
  eq c[2].last_column, 3

test 'Verify locations in string interpolation (in """string""", starting with line breaks)', ->
  [a, b, c] = getMatchingTokens '"""\n\n#{b}\nc"""', '"\\n"', 'b', '"\\nc"'

  eq a[2].first_line, 0
  eq a[2].first_column, 0
  eq a[2].last_line, 1
  eq a[2].last_column, 0

  eq b[2].first_line, 2
  eq b[2].first_column, 2
  eq b[2].last_line, 2
  eq b[2].last_column, 2

  eq c[2].first_line, 2
  eq c[2].first_column, 4
  eq c[2].last_line, 3
  eq c[2].last_column, 3

test 'Verify locations in string interpolation (in """string""", multiple interpolation)', ->
  [a, b, c] = getMatchingTokens '"""#{a}\nb\n#{c}"""', 'a', '"\\nb\\n"', 'c'

  eq a[2].first_line, 0
  eq a[2].first_column, 5
  eq a[2].last_line, 0
  eq a[2].last_column, 5

  eq b[2].first_line, 0
  eq b[2].first_column, 7
  eq b[2].last_line, 1
  eq b[2].last_column, 1

  eq c[2].first_line, 2
  eq c[2].first_column, 2
  eq c[2].last_line, 2
  eq c[2].last_column, 2

test 'Verify locations in string interpolation (in """string""", multiple interpolation, and starting with line breaks)', ->
  [a, b, c] = getMatchingTokens '"""\n\n#{a}\n\nb\n\n#{c}"""', 'a', '"\\n\\nb\\n\\n"', 'c'

  eq a[2].first_line, 2
  eq a[2].first_column, 2
  eq a[2].last_line, 2
  eq a[2].last_column, 2

  eq b[2].first_line, 2
  eq b[2].first_column, 4
  eq b[2].last_line, 5
  eq b[2].last_column, 0

  eq c[2].first_line, 6
  eq c[2].first_column, 2
  eq c[2].last_line, 6
  eq c[2].last_column, 2

test 'Verify locations in string interpolation (in """string""", multiple interpolation, and starting with line breaks)', ->
  [a, b, c] = getMatchingTokens '"""\n\n\n#{a}\n\n\nb\n\n\n#{c}"""', 'a', '"\\n\\n\\nb\\n\\n\\n"', 'c'

  eq a[2].first_line, 3
  eq a[2].first_column, 2
  eq a[2].last_line, 3
  eq a[2].last_column, 2

  eq b[2].first_line, 3
  eq b[2].first_column, 4
  eq b[2].last_line, 8
  eq b[2].last_column, 0

  eq c[2].first_line, 9
  eq c[2].first_column, 2
  eq c[2].last_line, 9
  eq c[2].last_column, 2

test 'Verify locations in heregex interpolation (in ///regex///, multiple interpolation)', ->
  [a, b, c] = getMatchingTokens '///#{a}b#{c}///', 'a', '"b"', 'c'

  eq a[2].first_line, 0
  eq a[2].first_column, 5
  eq a[2].last_line, 0
  eq a[2].last_column, 5

  eq b[2].first_line, 0
  eq b[2].first_column, 7
  eq b[2].last_line, 0
  eq b[2].last_column, 7

  eq c[2].first_line, 0
  eq c[2].first_column, 10
  eq c[2].last_line, 0
  eq c[2].last_column, 10

test 'Verify locations in heregex interpolation (in ///regex///, multiple interpolation)', ->
  [a, b, c] = getMatchingTokens '///a#{b}c///', '"a"', 'b', '"c"'

  eq a[2].first_line, 0
  eq a[2].first_column, 0
  eq a[2].last_line, 0
  eq a[2].last_column, 3

  eq b[2].first_line, 0
  eq b[2].first_column, 6
  eq b[2].last_line, 0
  eq b[2].last_column, 6

  eq c[2].first_line, 0
  eq c[2].first_column, 8
  eq c[2].last_line, 0
  eq c[2].last_column, 11

test 'Verify locations in heregex interpolation (in ///regex///, multiple interpolation and line breaks)', ->
  [a, b, c] = getMatchingTokens '///#{a}\nb\n#{c}///', 'a', '"b"', 'c'

  eq a[2].first_line, 0
  eq a[2].first_column, 5
  eq a[2].last_line, 0
  eq a[2].last_column, 5

  eq b[2].first_line, 0
  eq b[2].first_column, 7
  eq b[2].last_line, 1
  eq b[2].last_column, 1

  eq c[2].first_line, 2
  eq c[2].first_column, 2
  eq c[2].last_line, 2
  eq c[2].last_column, 2

test 'Verify locations in heregex interpolation (in ///regex///, multiple interpolation and line breaks)', ->
  [a, b, c] = getMatchingTokens '///#{a}\n\n\nb\n\n\n#{c}///', 'a', '"b"', 'c'

  eq a[2].first_line, 0
  eq a[2].first_column, 5
  eq a[2].last_line, 0
  eq a[2].last_column, 5

  eq b[2].first_line, 0
  eq b[2].first_column, 7
  eq b[2].last_line, 5
  eq b[2].last_column, 0

  eq c[2].first_line, 6
  eq c[2].first_column, 2
  eq c[2].last_line, 6
  eq c[2].last_column, 2

test 'Verify locations in heregex interpolation (in ///regex///, multiple interpolation and line breaks)', ->
  [a, b, c] = getMatchingTokens '///a\n\n\n#{b}\n\n\nc///', '"a"', 'b', '"c"'

  eq a[2].first_line, 0
  eq a[2].first_column, 0
  eq a[2].last_line, 2
  eq a[2].last_column, 0

  eq b[2].first_line, 3
  eq b[2].first_column, 2
  eq b[2].last_line, 3
  eq b[2].last_column, 2

  eq c[2].first_line, 3
  eq c[2].first_column, 4
  eq c[2].last_line, 6
  eq c[2].last_column, 3

test 'Verify locations in heregex interpolation (in ///regex///, multiple interpolation and line breaks and starting with linebreak)', ->
  [a, b, c] = getMatchingTokens '///\n#{a}\nb\n#{c}///', 'a', '"b"', 'c'

  eq a[2].first_line, 1
  eq a[2].first_column, 2
  eq a[2].last_line, 1
  eq a[2].last_column, 2

  eq b[2].first_line, 1
  eq b[2].first_column, 4
  eq b[2].last_line, 2
  eq b[2].last_column, 1

  eq c[2].first_line, 3
  eq c[2].first_column, 2
  eq c[2].last_line, 3
  eq c[2].last_column, 2

test 'Verify locations in heregex interpolation (in ///regex///, multiple interpolation and line breaks and starting with linebreak)', ->
  [a, b, c] = getMatchingTokens '///\n\n\n#{a}\n\n\nb\n\n\n#{c}///', 'a', '"b"', 'c'

  eq a[2].first_line, 3
  eq a[2].first_column, 2
  eq a[2].last_line, 3
  eq a[2].last_column, 2

  eq b[2].first_line, 3
  eq b[2].first_column, 4
  eq b[2].last_line, 8
  eq b[2].last_column, 0

  eq c[2].first_line, 9
  eq c[2].first_column, 2
  eq c[2].last_line, 9
  eq c[2].last_column, 2

test 'Verify locations in heregex interpolation (in ///regex///, multiple interpolation and line breaks and starting with linebreak)', ->
  [a, b, c] = getMatchingTokens '///\n\n\na\n\n\n#{b}\n\n\nc///', '"a"', 'b', '"c"'

  eq a[2].first_line, 0
  eq a[2].first_column, 0
  eq a[2].last_line, 5
  eq a[2].last_column, 0

  eq b[2].first_line, 6
  eq b[2].first_column, 2
  eq b[2].last_line, 6
  eq b[2].last_column, 2

  eq c[2].first_line, 6
  eq c[2].first_column, 4
  eq c[2].last_line, 9
  eq c[2].last_column, 3

test "#3822: Simple string/regex start/end should include delimiters", ->
  [stringToken] = CoffeeScript.tokens "'string'"
  eq stringToken[2].first_line, 0
  eq stringToken[2].first_column, 0
  eq stringToken[2].last_line, 0
  eq stringToken[2].last_column, 7

  [regexToken] = CoffeeScript.tokens "/regex/"
  eq regexToken[2].first_line, 0
  eq regexToken[2].first_column, 0
  eq regexToken[2].last_line, 0
  eq regexToken[2].last_column, 6

test "#3621: Multiline regex and manual `Regex` call with interpolation should
      result in the same tokens", ->
  tokensA = CoffeeScript.tokens '(RegExp(".*#{a}[0-9]"))'
  tokensB = CoffeeScript.tokens '///.*#{a}[0-9]///'
  eq tokensA.length, tokensB.length
  for i in [0...tokensA.length] by 1
    tokenA = tokensA[i]
    tokenB = tokensB[i]
    eq tokenA[0], tokenB[0] unless tokenB[0] in ['REGEX_START', 'REGEX_END']
    eq tokenA[1], tokenB[1]
    unless tokenA[0] is 'STRING_START' or tokenB[0] is 'REGEX_START'
      eq tokenA.origin?[1], tokenB.origin?[1]
    eq tokenA.stringEnd, tokenB.stringEnd

test "Verify tokens have locations that are in order", ->
  source = '''
    a {
      b: ->
        return c d,
          if e
            f
    }
    g
  '''
  tokens = CoffeeScript.tokens source
  lastToken = null
  for token in tokens
    if lastToken
      ok token[2].first_line >= lastToken[2].last_line
      if token[2].first_line == lastToken[2].last_line
        ok token[2].first_column >= lastToken[2].last_column
    lastToken = token

test "Verify OUTDENT tokens are located at the end of the previous token", ->
  source = '''
    SomeArr = [ ->
      if something
        lol =
          count: 500
    ]
  '''
  tokens = CoffeeScript.tokens source
  [..., number, curly, outdent1, outdent2, outdent3, bracket, terminator] = tokens
  eq number[0], 'NUMBER'
  for outdent in [outdent1, outdent2, outdent3]
    eq outdent[0], 'OUTDENT'
    eq outdent[2].first_line, number[2].last_line
    eq outdent[2].first_column, number[2].last_column
    eq outdent[2].last_line, number[2].last_line
    eq outdent[2].last_column, number[2].last_column

test "Verify OUTDENT and CALL_END tokens are located at the end of the previous token", ->
  source = '''
    a = b {
      c: ->
        d e,
          if f
            g {},
              if h
                i {}
    }
  '''
  tokens = CoffeeScript.tokens source
  [..., closeCurly1, callEnd1, outdent1, outdent2, callEnd2, outdent3, outdent4,
    callEnd3, outdent5, outdent6, closeCurly2, callEnd4, terminator] = tokens
  eq closeCurly1[0], '}'
  assertAtCloseCurly = (token) ->
    eq token[2].first_line, closeCurly1[2].last_line
    eq token[2].first_column, closeCurly1[2].last_column
    eq token[2].last_line, closeCurly1[2].last_line
    eq token[2].last_column, closeCurly1[2].last_column

  for token in [outdent1, outdent2, outdent3, outdent4, outdent5, outdent6]
    eq token[0], 'OUTDENT'
    assertAtCloseCurly(token)
  for token in [callEnd1, callEnd2, callEnd3]
    eq token[0], 'CALL_END'
    assertAtCloseCurly(token)

test "Verify generated } tokens are located at the end of the previous token", ->
  source = '''
    a(b, ->
      c: () ->
        if d
          e
    )
  '''
  tokens = CoffeeScript.tokens source
  [..., identifier, outdent1, outdent2, closeCurly, outdent3, callEnd,
    terminator] = tokens
  eq identifier[0], 'IDENTIFIER'
  assertAtIdentifier = (token) ->
    eq token[2].first_line, identifier[2].last_line
    eq token[2].first_column, identifier[2].last_column
    eq token[2].last_line, identifier[2].last_line
    eq token[2].last_column, identifier[2].last_column

  for token in [outdent1, outdent2, closeCurly, outdent3]
    assertAtIdentifier(token)

test "Verify real CALL_END tokens have the right position", ->
  source = '''
    a()
  '''
  tokens = CoffeeScript.tokens source
  [identifier, callStart, callEnd, terminator] = tokens
  startIndex = identifier[2].first_column
  eq identifier[2].last_column, startIndex
  eq callStart[2].first_column, startIndex + 1
  eq callStart[2].last_column, startIndex + 1
  eq callEnd[2].first_column, startIndex + 2
  eq callEnd[2].last_column, startIndex + 2

test "Verify normal heredocs have the right position", ->
  source = '''
    """
    a"""
  '''
  [stringToken] = CoffeeScript.tokens source
  eq stringToken[2].first_line, 0
  eq stringToken[2].first_column, 0
  eq stringToken[2].last_line, 1
  eq stringToken[2].last_column, 3

test "Verify heredocs ending with a newline have the right position", ->
  source = '''
    """
    a
    """
  '''
  [stringToken] = CoffeeScript.tokens source
  eq stringToken[2].first_line, 0
  eq stringToken[2].first_column, 0
  eq stringToken[2].last_line, 2
  eq stringToken[2].last_column, 2

test "Verify indented heredocs have the right position", ->
  source = '''
    ->
      """
        a
      """
  '''
  [arrow, indent, stringToken] = CoffeeScript.tokens source
  eq stringToken[2].first_line, 1
  eq stringToken[2].first_column, 2
  eq stringToken[2].last_line, 3
  eq stringToken[2].last_column, 4

test "Verify heregexes with interpolations have the right ending position", ->
  source = '''
    [a ///#{b}///g]
  '''
  [..., stringEnd, comma, flagsString, regexCallEnd, regexEnd, fnCallEnd,
    arrayEnd, terminator] = CoffeeScript.tokens source

  eq comma[0], ','
  eq arrayEnd[0], ']'

  assertColumn = (token, column) ->
    eq token[2].first_line, 0
    eq token[2].first_column, column
    eq token[2].last_line, 0
    eq token[2].last_column, column

  arrayEndColumn = arrayEnd[2].first_column
  for token in [comma, flagsString]
    assertColumn token, arrayEndColumn - 2
  for token in [regexCallEnd, regexEnd, fnCallEnd]
    assertColumn token, arrayEndColumn - 1
  assertColumn arrayEnd, arrayEndColumn

test "Verify all tokens get a location", ->
  doesNotThrow ->
    tokens = CoffeeScript.tokens testScript
    for token in tokens
        ok !!token[2]

</script>
<script type="text/x-coffeescript" class="test" id="modules">
# Modules, a.k.a. ES2015 import/export
# ------------------------------------
#
# Remember, we’re not *resolving* modules, just outputting valid ES2015 syntax.


# This is the CoffeeScript import and export syntax, closely modeled after the ES2015 syntax
# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export

# import "module-name"
# import defaultMember from "module-name"
# import * as name from "module-name"
# import { } from "module-name"
# import { member } from "module-name"
# import { member as alias } from "module-name"
# import { member1, member2 as alias2, … } from "module-name"
# import defaultMember, * as name from "module-name"
# import defaultMember, { … } from "module-name"

# export default expression
# export class name
# export { }
# export { name }
# export { name as exportedName }
# export { name as default }
# export { name1, name2 as exportedName2, name3 as default, … }
#
# export * from "module-name"
# export { … } from "module-name"
#
# As a subsitute for `export var name = …` and `export function name {}`,
# CoffeeScript also supports:
# export name = …

# CoffeeScript also supports optional commas within `{ … }`.


# Import statements

test "backticked import statement", ->
  input = """
    if Meteor.isServer
      `import { foo, bar as baz } from 'lib'`"""
  output = """
    if (Meteor.isServer) {
      import { foo, bar as baz } from 'lib';
    }"""
  eq toJS(input), output

test "import an entire module for side effects only, without importing any bindings", ->
  input = "import 'lib'"
  output = "import 'lib';"
  eq toJS(input), output

test "import default member from module, adding the member to the current scope", ->
  input = """
    import foo from 'lib'
    foo.fooMethod()"""
  output = """
    import foo from 'lib';

    foo.fooMethod();"""
  eq toJS(input), output

test "import an entire module's contents as an alias, adding the alias to the current scope", ->
  input = """
    import * as foo from 'lib'
    foo.fooMethod()"""
  output = """
    import * as foo from 'lib';

    foo.fooMethod();"""
  eq toJS(input), output

test "import empty object", ->
  input = "import { } from 'lib'"
  output = "import {} from 'lib';"
  eq toJS(input), output

test "import empty object", ->
  input = "import {} from 'lib'"
  output = "import {} from 'lib';"
  eq toJS(input), output

test "import a single member of a module, adding the member to the current scope", ->
  input = """
    import { foo } from 'lib'
    foo.fooMethod()"""
  output = """
    import {
      foo
    } from 'lib';

    foo.fooMethod();"""
  eq toJS(input), output

test "import a single member of a module as an alias, adding the alias to the current scope", ->
  input = """
    import { foo as bar } from 'lib'
    bar.barMethod()"""
  output = """
    import {
      foo as bar
    } from 'lib';

    bar.barMethod();"""
  eq toJS(input), output

test "import multiple members of a module, adding the members to the current scope", ->
  input = """
    import { foo, bar } from 'lib'
    foo.fooMethod()
    bar.barMethod()"""
  output = """
    import {
      foo,
      bar
    } from 'lib';

    foo.fooMethod();

    bar.barMethod();"""
  eq toJS(input), output

test "import multiple members of a module where some are aliased, adding the members or aliases to the current scope", ->
  input = """
    import { foo, bar as baz } from 'lib'
    foo.fooMethod()
    baz.bazMethod()"""
  output = """
    import {
      foo,
      bar as baz
    } from 'lib';

    foo.fooMethod();

    baz.bazMethod();"""
  eq toJS(input), output

test "import default member and other members of a module, adding the members to the current scope", ->
  input = """
    import foo, { bar, baz as qux } from 'lib'
    foo.fooMethod()
    bar.barMethod()
    qux.quxMethod()"""
  output = """
    import foo, {
      bar,
      baz as qux
    } from 'lib';

    foo.fooMethod();

    bar.barMethod();

    qux.quxMethod();"""
  eq toJS(input), output

test "import default member from a module as well as the entire module's contents as an alias, adding the member and alias to the current scope", ->
  input = """
    import foo, * as bar from 'lib'
    foo.fooMethod()
    bar.barMethod()"""
  output = """
    import foo, * as bar from 'lib';

    foo.fooMethod();

    bar.barMethod();"""
  eq toJS(input), output

test "multiline simple import", ->
  input = """
    import {
      foo,
      bar as baz
    } from 'lib'"""
  output = """
    import {
      foo,
      bar as baz
    } from 'lib';"""
  eq toJS(input), output

test "multiline complex import", ->
  input = """
    import foo, {
      bar,
      baz as qux
    } from 'lib'"""
  output = """
    import foo, {
      bar,
      baz as qux
    } from 'lib';"""
  eq toJS(input), output

test "import with optional commas", ->
  input = "import { foo, bar, } from 'lib'"
  output = """
    import {
      foo,
      bar
    } from 'lib';"""
  eq toJS(input), output

test "multiline import without commas", ->
  input = """
    import {
      foo
      bar
    } from 'lib'"""
  output = """
    import {
      foo,
      bar
    } from 'lib';"""
  eq toJS(input), output

test "multiline import with optional commas", ->
  input = """
    import {
      foo,
      bar,
    } from 'lib'"""
  output = """
    import {
      foo,
      bar
    } from 'lib';"""
  eq toJS(input), output

test "a variable can be assigned after an import", ->
  input = """
    import { foo } from 'lib'
    bar = 5"""
  output = """
    var bar;

    import {
      foo
    } from 'lib';

    bar = 5;"""
  eq toJS(input), output

test "variables can be assigned before and after an import", ->
  input = """
    foo = 5
    import { bar } from 'lib'
    baz = 7"""
  output = """
    var baz, foo;

    foo = 5;

    import {
      bar
    } from 'lib';

    baz = 7;"""
  eq toJS(input), output

# Export statements

test "export empty object", ->
  input = "export { }"
  output = "export {};"
  eq toJS(input), output

test "export empty object", ->
  input = "export {}"
  output = "export {};"
  eq toJS(input), output

test "export named members within an object", ->
  input = "export { foo, bar }"
  output = """
    export {
      foo,
      bar
    };"""
  eq toJS(input), output

test "export named members as aliases, within an object", ->
  input = "export { foo as bar, baz as qux }"
  output = """
    export {
      foo as bar,
      baz as qux
    };"""
  eq toJS(input), output

test "export named members within an object, with an optional comma", ->
  input = "export { foo, bar, }"
  output = """
    export {
      foo,
      bar
    };"""
  eq toJS(input), output

test "multiline export named members within an object", ->
  input = """
    export {
      foo,
      bar
    }"""
  output = """
    export {
      foo,
      bar
    };"""
  eq toJS(input), output

test "multiline export named members within an object, with an optional comma", ->
  input = """
    export {
      foo,
      bar,
    }"""
  output = """
    export {
      foo,
      bar
    };"""
  eq toJS(input), output

test "export default string", ->
  input = "export default 'foo'"
  output = "export default 'foo';"
  eq toJS(input), output

test "export default number", ->
  input = "export default 5"
  output = "export default 5;"
  eq toJS(input), output

test "export default object", ->
  input = "export default { foo: 'bar', baz: 'qux' }"
  output = """
    export default {
      foo: 'bar',
      baz: 'qux'
    };"""
  eq toJS(input), output

test "export default implicit object", ->
  input = "export default foo: 'bar', baz: 'qux'"
  output = """
    export default {
      foo: 'bar',
      baz: 'qux'
    };"""
  eq toJS(input), output

test "export default multiline implicit object", ->
  input = """
    export default
      foo: 'bar',
      baz: 'qux'
    """
  output = """
    export default {
      foo: 'bar',
      baz: 'qux'
    };"""
  eq toJS(input), output

test "export default assignment expression", ->
  input = "export default foo = 'bar'"
  output = """
    var foo;

    export default foo = 'bar';"""
  eq toJS(input), output

test "export assignment expression", ->
  input = "export foo = 'bar'"
  output = "export var foo = 'bar';"
  eq toJS(input), output

test "export multiline assignment expression", ->
  input = """
    export foo =
    'bar'"""
  output = "export var foo = 'bar';"
  eq toJS(input), output

test "export multiline indented assignment expression", ->
  input = """
    export foo =
      'bar'"""
  output = "export var foo = 'bar';"
  eq toJS(input), output

test "export default function", ->
  input = "export default ->"
  output = "export default function() {};"
  eq toJS(input), output

test "export default multiline function", ->
  input = """
    export default (foo) ->
      console.log foo"""
  output = """
    export default function(foo) {
      return console.log(foo);
    };"""
  eq toJS(input), output

test "export assignment function", ->
  input = """
    export foo = (bar) ->
      console.log bar"""
  output = """
    export var foo = function(bar) {
      return console.log(bar);
    };"""
  eq toJS(input), output

test "export assignment function which contains assignments in its body", ->
  input = """
    export foo = (bar) ->
      baz = '!'
      console.log bar + baz"""
  output = """
    export var foo = function(bar) {
      var baz;
      baz = '!';
      return console.log(bar + baz);
    };"""
  eq toJS(input), output

test "export default predefined function", ->
  input = """
    foo = (bar) ->
      console.log bar
    export default foo"""
  output = """
    var foo;

    foo = function(bar) {
      return console.log(bar);
    };

    export default foo;"""
  eq toJS(input), output

# Uncomment this test once ES2015+ `class` support is added

# test "export default class", ->
#   input = """
#     export default class foo extends bar
#       baz: ->
#         console.log 'hello, world!'"""
#   output = """
#     export default class foo extends bar {
#       baz: function {
#         return console.log('hello, world!');
#       }
#     }"""
#   eq toJS(input), output

# Very limited tests for now, testing that `export class foo` either compiles
# identically (ES2015+) or at least into some function, leaving the specifics
# vague in case the CoffeeScript `class` interpretation changes
test "export class", ->
  input = """
    export class foo
      baz: ->
        console.log 'hello, world!'"""
  output = toJS input
  ok /^export (class foo|var foo = \(function)/.test toJS input

test "export class that extends", ->
  input = """
    export class foo extends bar
      baz: ->
        console.log 'hello, world!'"""
  output = toJS input
  ok /export (class foo|var foo = \(function)/.test(output) and \
    not /var foo(;|,)/.test output

test "export default class that extends", ->
  input = """
    export default class foo extends bar
      baz: ->
        console.log 'hello, world!'"""
  ok /export default (class foo|foo = \(function)/.test toJS input

test "export default named member, within an object", ->
  input = "export { foo as default, bar }"
  output = """
    export {
      foo as default,
      bar
    };"""
  eq toJS(input), output


# Import and export in the same statement

test "export an entire module's contents", ->
  input = "export * from 'lib'"
  output = "export * from 'lib';"
  eq toJS(input), output

test "export members imported from another module", ->
  input = "export { foo, bar } from 'lib'"
  output = """
    export {
      foo,
      bar
    } from 'lib';"""
  eq toJS(input), output

test "export as aliases members imported from another module", ->
  input = "export { foo as bar, baz as qux } from 'lib'"
  output = """
    export {
      foo as bar,
      baz as qux
    } from 'lib';"""
  eq toJS(input), output

test "export list can contain CoffeeScript keywords", ->
  input = "export { unless } from 'lib'"
  output = """
    export {
      unless
    } from 'lib';"""
  eq toJS(input), output

test "export list can contain CoffeeScript keywords when aliasing", ->
  input = "export { when as bar, baz as unless } from 'lib'"
  output = """
    export {
      when as bar,
      baz as unless
    } from 'lib';"""
  eq toJS(input), output


# Edge cases

test "multiline import with comments", ->
  input = """
    import {
      foo, # Not as good as bar
      bar as baz # I prefer qux
    } from 'lib'"""
  output = """
    import {
      foo,
      bar as baz
    } from 'lib';"""
  eq toJS(input), output

test "`from` not part of an import or export statement can still be assigned", ->
  from = 5
  eq 5, from

test "a variable named `from` can be assigned after an import", ->
  input = """
    import { foo } from 'lib'
    from = 5"""
  output = """
    var from;

    import {
      foo
    } from 'lib';

    from = 5;"""
  eq toJS(input), output

test "`from` can be assigned after a multiline import", ->
  input = """
    import {
      foo
    } from 'lib'
    from = 5"""
  output = """
    var from;

    import {
      foo
    } from 'lib';

    from = 5;"""
  eq toJS(input), output

test "`from` can be imported as a member name", ->
  input = "import { from } from 'lib'"
  output = """
    import {
      from
    } from 'lib';"""
  eq toJS(input), output

test "`from` can be imported as a member name and aliased", ->
  input = "import { from as foo } from 'lib'"
  output = """
    import {
      from as foo
    } from 'lib';"""
  eq toJS(input), output

test "`from` can be used as an alias name", ->
  input = "import { foo as from } from 'lib'"
  output = """
    import {
      foo as from
    } from 'lib';"""
  eq toJS(input), output

test "`as` can be imported as a member name", ->
  input = "import { as } from 'lib'"
  output = """
    import {
      as
    } from 'lib';"""
  eq toJS(input), output

test "`as` can be imported as a member name and aliased", ->
  input = "import { as as foo } from 'lib'"
  output = """
    import {
      as as foo
    } from 'lib';"""
  eq toJS(input), output

test "`as` can be used as an alias name", ->
  input = "import { foo as as } from 'lib'"
  output = """
    import {
      foo as as
    } from 'lib';"""
  eq toJS(input), output

test "CoffeeScript keywords can be used as imported names in import lists", ->
  input = """
    import { unless as bar } from 'lib'
    bar.barMethod()"""
  output = """
    import {
      unless as bar
    } from 'lib';

    bar.barMethod();"""
  eq toJS(input), output

test "`*` can be used in an expression on the same line as an export keyword", ->
  input = "export foo = (x) -> x * x"
  output = """
    export var foo = function(x) {
      return x * x;
    };"""
  eq toJS(input), output
  input = "export default foo = (x) -> x * x"
  output = """
    var foo;

    export default foo = function(x) {
      return x * x;
    };"""
  eq toJS(input), output

test "`*` and `from` can be used in an export default expression", ->
  input = """
    export default foo.extend
      bar: ->
        from = 5
        from = from * 3"""
  output = """
    export default foo.extend({
      bar: function() {
        var from;
        from = 5;
        return from = from * 3;
      }
    });"""
  eq toJS(input), output

test "wrapped members can be imported multiple times if aliased", ->
  input = "import { foo, foo as bar } from 'lib'"
  output = """
    import {
      foo,
      foo as bar
    } from 'lib';"""
  eq toJS(input), output

test "default and wrapped members can be imported multiple times if aliased", ->
  input = "import foo, { foo as bar } from 'lib'"
  output = """
    import foo, {
      foo as bar
    } from 'lib';"""
  eq toJS(input), output

test "import a member named default", ->
  input = "import { default } from 'lib'"
  output = """
    import {
      default
    } from 'lib';"""
  eq toJS(input), output

test "import an aliased member named default", ->
  input = "import { default as def } from 'lib'"
  output = """
    import {
      default as def
    } from 'lib';"""
  eq toJS(input), output

test "export a member named default", ->
  input = "export { default }"
  output = """
    export {
      default
    };"""
  eq toJS(input), output

test "export an aliased member named default", ->
  input = "export { def as default }"
  output = """
    export {
      def as default
    };"""
  eq toJS(input), output

test "import an imported member named default", ->
  input = "import { default } from 'lib'"
  output = """
    import {
      default
    } from 'lib';"""
  eq toJS(input), output

test "import an imported aliased member named default", ->
  input = "import { default as def } from 'lib'"
  output = """
    import {
      default as def
    } from 'lib';"""
  eq toJS(input), output

test "export an imported member named default", ->
  input = "export { default } from 'lib'"
  output = """
    export {
      default
    } from 'lib';"""
  eq toJS(input), output

test "export an imported aliased member named default", ->
  input = "export { default as def } from 'lib'"
  output = """
    export {
      default as def
    } from 'lib';"""
  eq toJS(input), output

test "#4394: export shouldn't prevent variable declarations", ->
  input = """
    x = 1
    export { x }
  """
  output = """
    var x;

    x = 1;

    export {
      x
    };
  """
  eq toJS(input), output

test "#4451: `default` in an export statement is only treated as a keyword when it follows `export` or `as`", ->
  input = "export default { default: 1 }"
  output = """
    export default {
      "default": 1
    };
  """
  eq toJS(input), output

test "#4491: import- and export-specific lexing should stop after import/export statement", ->
  input = """
    import {
      foo,
      bar as baz
    } from 'lib'

    foo as
    3 * as 4
    from 'foo'
    """
  output = """
    import {
      foo,
      bar as baz
    } from 'lib';

    foo(as);

    3 * as(4);

    from('foo');
    """
  eq toJS(input), output

  input = """
    import { foo, bar as baz } from 'lib'

    foo as
    3 * as 4
    from 'foo'
    """
  output = """
    import {
      foo,
      bar as baz
    } from 'lib';

    foo(as);

    3 * as(4);

    from('foo');
    """
  eq toJS(input), output

  input = """
    import * as lib from 'lib'

    foo as
    3 * as 4
    from 'foo'
    """
  output = """
    import * as lib from 'lib';

    foo(as);

    3 * as(4);

    from('foo');
    """
  eq toJS(input), output

  input = """
    export {
      foo,
      bar
    }

    foo as
    3 * as 4
    from 'foo'
    """
  output = """
    export {
      foo,
      bar
    };

    foo(as);

    3 * as(4);

    from('foo');
    """
  eq toJS(input), output

  input = """
    export * from 'lib'

    foo as
    3 * as 4
    from 'foo'
    """
  output = """
    export * from 'lib';

    foo(as);

    3 * as(4);

    from('foo');
    """
  eq toJS(input), output

</script>
<script type="text/x-coffeescript" class="test" id="numbers">
# Number Literals
# ---------------

# * Decimal Integer Literals
# * Octal Integer Literals
# * Hexadecimal Integer Literals
# * Scientific Notation Integer Literals
# * Scientific Notation Non-Integer Literals
# * Non-Integer Literals
# * Binary Integer Literals


# Binary Integer Literals
# Binary notation is understood as would be decimal notation.

test "Parser recognises binary numbers", ->
  eq 4, 0b100

# Decimal Integer Literals

test "call methods directly on numbers", ->
  eq 4, 4.valueOf()
  eq '11', 4.toString 3

eq -1, 3 -4

#764: Numbers should be indexable
eq Number::toString, 42['toString']

eq Number::toString, 42.toString

eq Number::toString, 2e308['toString'] # Infinity


# Non-Integer Literals

# Decimal number literals.
value = .25 + .75
ok value is 1
value = 0.0 + -.25 - -.75 + 0.0
ok value is 0.5

#764: Numbers should be indexable
eq Number::toString,   4['toString']
eq Number::toString, 4.2['toString']
eq Number::toString, .42['toString']
eq Number::toString, (4)['toString']

eq Number::toString,   4.toString
eq Number::toString, 4.2.toString
eq Number::toString, .42.toString
eq Number::toString, (4).toString

test '#1168: leading floating point suppresses newline', ->
  eq 1, do ->
    1
    .5 + 0.5

test "Python-style octal literal notation '0o777'", ->
  eq 511, 0o777
  eq 1, 0o1
  eq 1, 0o00001
  eq parseInt('0777', 8), 0o777
  eq '777', 0o777.toString 8
  eq 4, 0o4.valueOf()
  eq Number::toString, 0o777['toString']
  eq Number::toString, 0o777.toString

test "#2060: Disallow uppercase radix prefixes and exponential notation", ->
  for char in ['b', 'o', 'x', 'e']
    program = "0#{char}0"
    doesNotThrow -> CoffeeScript.compile program, bare: yes
    throws -> CoffeeScript.compile program.toUpperCase(), bare: yes

test "#2224: hex literals with 0b or B or E", ->
  eq 176, 0x0b0
  eq 177, 0x0B1
  eq 225, 0xE1

test "Infinity", ->
  eq Infinity, CoffeeScript.eval "0b#{Array(1024 + 1).join('1')}"
  eq Infinity, CoffeeScript.eval "0o#{Array(342 + 1).join('7')}"
  eq Infinity, CoffeeScript.eval "0x#{Array(256 + 1).join('f')}"
  eq Infinity, CoffeeScript.eval Array(500 + 1).join('9')
  eq Infinity, 2e308

test "NaN", ->
  ok isNaN 1/NaN

</script>
<script type="text/x-coffeescript" class="test" id="objects">
# Object Literals
# ---------------

# TODO: refactor object literal tests
# TODO: add indexing and method invocation tests: {a}['a'] is a, {a}.a()

trailingComma = {k1: "v1", k2: 4, k3: (-> true),}
ok trailingComma.k3() and (trailingComma.k2 is 4) and (trailingComma.k1 is "v1")

ok {a: (num) -> num is 10 }.a 10

moe = {
  name:  'Moe'
  greet: (salutation) ->
    salutation + " " + @name
  hello: ->
    @['greet'] "Hello"
  10: 'number'
}
ok moe.hello() is "Hello Moe"
ok moe[10] is 'number'
moe.hello = ->
  this['greet'] "Hello"
ok moe.hello() is 'Hello Moe'

obj = {
  is:     -> yes,
  'not':  -> no,
}
ok obj.is()
ok not obj.not()

### Top-level object literal... ###
obj: 1
### ...doesn't break things. ###

# Object literals should be able to include keywords.
obj = {class: 'höt'}
obj.function = 'dog'
ok obj.class + obj.function is 'hötdog'

# Implicit objects as part of chained calls.
pluck = (x) -> x.a
eq 100, pluck pluck pluck a: a: a: 100


test "YAML-style object literals", ->
  obj =
    a: 1
    b: 2
  eq 1, obj.a
  eq 2, obj.b

  config =
    development:
      server: 'localhost'
      timeout: 10

    production:
      server: 'dreamboat'
      timeout: 1000

  ok config.development.server  is 'localhost'
  ok config.production.server   is 'dreamboat'
  ok config.development.timeout is 10
  ok config.production.timeout  is 1000

obj =
  a: 1,
  b: 2,
ok obj.a is 1
ok obj.b is 2

# Implicit objects nesting.
obj =
  options:
    value: yes
  fn: ->
    {}
    null
ok obj.options.value is yes
ok obj.fn() is null

# Implicit objects with wacky indentation:
obj =
  'reverse': (obj) ->
    Array.prototype.reverse.call obj
  abc: ->
    @reverse(
      @reverse @reverse ['a', 'b', 'c'].reverse()
    )
  one: [1, 2,
    a: 'b'
  3, 4]
  red:
    orange:
          yellow:
                  green: 'blue'
    indigo: 'violet'
  misdent: [[],
  [],
                  [],
      []]
ok obj.abc().join(' ') is 'a b c'
ok obj.one.length is 5
ok obj.one[4] is 4
ok obj.one[2].a is 'b'
ok (key for key of obj.red).length is 2
ok obj.red.orange.yellow.green is 'blue'
ok obj.red.indigo is 'violet'
ok obj.misdent.toString() is ',,,'

#542: Objects leading expression statement should be parenthesized.
{f: -> ok yes }.f() + 1

# String-keyed objects shouldn't suppress newlines.
one =
  '>!': 3
six: -> 10
ok not one.six

# Shorthand objects with property references.
obj =
  ### comment one ###
  ### comment two ###
  one: 1
  two: 2
  object: -> {@one, @two}
  list:   -> [@one, @two]
result = obj.object()
eq result.one, 1
eq result.two, 2
eq result.two, obj.list()[1]

third = (a, b, c) -> c
obj =
  one: 'one'
  two: third 'one', 'two', 'three'
ok obj.one is 'one'
ok obj.two is 'three'

test "invoking functions with implicit object literals", ->
  generateGetter = (prop) -> (obj) -> obj[prop]
  getA = generateGetter 'a'
  getArgs = -> arguments
  a = b = 30

  result = getA
    a: 10
  eq 10, result

  result = getA
    "a": 20
  eq 20, result

  result = getA a,
    b:1
  eq undefined, result

  result = getA b:1,
  a:43
  eq 43, result

  result = getA b:1,
    a:62
  eq undefined, result

  result = getA
    b:1
    a
  eq undefined, result

  result = getA
    a:
      b:2
    b:1
  eq 2, result.b

  result = getArgs
    a:1
    b
    c:1
  ok result.length is 3
  ok result[2].c is 1

  result = getA b: 13, a: 42, 2
  eq 42, result

  result = getArgs a:1, (1 + 1)
  ok result[1] is 2

  result = getArgs a:1, b
  ok result.length is 2
  ok result[1] is 30

  result = getArgs a:1, b, b:1, a
  ok result.length is 4
  ok result[2].b is 1

  throws -> CoffeeScript.compile "a = b:1, c"

test "some weird indentation in YAML-style object literals", ->
  two = (a, b) -> b
  obj = then two 1,
    1: 1
    a:
      b: ->
        fn c,
          d: e
    f: 1
  eq 1, obj[1]

test "#1274: `{} = a()` compiles to `false` instead of `a()`", ->
  a = false
  fn = -> a = true
  {} = fn()
  ok a

test "#1436: `for` etc. work as normal property names", ->
  obj = {}
  eq no, obj.hasOwnProperty 'for'
  obj.for = 'foo' of obj
  eq yes, obj.hasOwnProperty 'for'

test "#2706, Un-bracketed object as argument causes inconsistent behavior", ->
  foo = (x, y) -> y
  bar = baz: yes

  eq yes, foo x: 1, bar.baz

test "#2608, Allow inline objects in arguments to be followed by more arguments", ->
  foo = (x, y) -> y

  eq yes, foo x: 1, y: 2, yes

test "#2308, a: b = c:1", ->
  foo = a: b = c: yes
  eq b.c, yes
  eq foo.a.c, yes

test "#2317, a: b c: 1", ->
  foo = (x) -> x
  bar = a: foo c: yes
  eq bar.a.c, yes

test "#1896, a: func b, {c: d}", ->
  first = (x) -> x
  second = (x, y) -> y
  third = (x, y, z) -> z

  one = 1
  two = 2
  three = 3
  four = 4

  foo = a: second one, {c: two}
  eq foo.a.c, two

  bar = a: second one, c: two
  eq bar.a.c, two

  baz = a: second one, {c: two}, e: first first h: three
  eq baz.a.c, two

  qux = a: third one, {c: two}, e: first first h: three
  eq qux.a.e.h, three

  quux = a: third one, {c: two}, e: first(three), h: four
  eq quux.a.e, three
  eq quux.a.h, four

  corge = a: third one, {c: two}, e: second three, h: four
  eq corge.a.e.h, four

test "Implicit objects, functions and arrays", ->
  first  = (x) -> x
  second = (x, y) -> y

  foo = [
    1
    one: 1
    two: 2
    three: 3
    more:
      four: 4
      five: 5, six: 6
    2, 3, 4
    5]
  eq foo[2], 2
  eq foo[1].more.six, 6

  bar = [
    1
    first first first second 1,
      one: 1, twoandthree: twoandthree: two: 2, three: 3
      2,
    2
    one: 1
    two: 2
    three: first second ->
      no
    , ->
      3
    3
    4]
  eq bar[2], 2
  eq bar[1].twoandthree.twoandthree.two, 2
  eq bar[3].three(), 3
  eq bar[4], 3

test "#2549, Brace-less Object Literal as a Second Operand on a New Line", ->
  foo = no or
    one: 1
    two: 2
    three: 3
  eq foo.one, 1

  bar = yes and one: 1
  eq bar.one, 1

  baz = null ?
    one: 1
    two: 2
  eq baz.two, 2

test "#2757, Nested", ->
  foo =
    bar:
      one: 1,
  eq foo.bar.one, 1

  baz =
    qux:
      one: 1,
    corge:
      two: 2,
      three: three: three: 3,
    xyzzy:
      thud:
        four:
          four: 4,
      five: 5,

  eq baz.qux.one, 1
  eq baz.corge.three.three.three, 3
  eq baz.xyzzy.thud.four.four, 4
  eq baz.xyzzy.five, 5

test "#1865, syntax regression 1.1.3", ->
  foo = (x, y) -> y

  bar = a: foo (->),
    c: yes
  eq bar.a.c, yes

  baz = a: foo (->), c: yes
  eq baz.a.c, yes


test "#1322: implicit call against implicit object with block comments", ->
  ((obj, arg) ->
    eq obj.x * obj.y, 6
    ok not arg
  )
    ###
    x
    ###
    x: 2
    ### y ###
    y: 3

test "#1513: Top level bare objs need to be wrapped in parens for unary and existence ops", ->
  doesNotThrow -> CoffeeScript.run "{}?", bare: true
  doesNotThrow -> CoffeeScript.run "{}.a++", bare: true

test "#1871: Special case for IMPLICIT_END in the middle of an implicit object", ->
  result = 'result'
  ident = (x) -> x

  result = ident one: 1 if false

  eq result, 'result'

  result = ident
    one: 1
    two: 2 for i in [1..3]

  eq result.two.join(' '), '2 2 2'

test "#1871: implicit object closed by IMPLICIT_END in implicit returns", ->
  ob = do ->
    a: 1 if no
  eq ob, undefined

  # instead these return an object
  func = ->
    key:
      i for i in [1, 2, 3]

  eq func().key.join(' '), '1 2 3'

  func = ->
    key: (i for i in [1, 2, 3])

  eq func().key.join(' '), '1 2 3'

test "#1961, #1974, regression with compound assigning to an implicit object", ->

  obj = null

  obj ?=
    one: 1
    two: 2

  eq obj.two, 2

  obj = null

  obj or=
    three: 3
    four: 4

  eq obj.four, 4

test "#2207: Immediate implicit closes don't close implicit objects", ->
  func = ->
    key: for i in [1, 2, 3] then i

  eq func().key.join(' '), '1 2 3'

test "#3216: For loop declaration as a value of an implicit object", ->
  test = [0..2]
  ob =
    a: for v, i in test then i
    b: for v, i in test then i
    c: for v in test by 1 then v
    d: for v in test when true then v
  arrayEq ob.a, test
  arrayEq ob.b, test
  arrayEq ob.c, test
  arrayEq ob.d, test

test 'inline implicit object literals within multiline implicit object literals', ->
  x =
    a: aa: 0
    b: 0
  eq 0, x.b
  eq 0, x.a.aa

test "object keys with interpolations", ->
  # Simple cases.
  a = 'a'
  obj = "#{a}": yes
  eq obj.a, yes
  obj = {"#{a}": yes}
  eq obj.a, yes
  obj = {"#{a}"}
  eq obj.a, 'a'
  obj = {"#{5}"}
  eq obj[5], '5' # Note that the value is a string, just like the key.

  # Commas in implicit object.
  obj = "#{'a'}": 1, b: 2
  deepEqual obj, {a: 1, b: 2}
  obj = a: 1, "#{'b'}": 2
  deepEqual obj, {a: 1, b: 2}
  obj = "#{'a'}": 1, "#{'b'}": 2
  deepEqual obj, {a: 1, b: 2}

  # Commas in explicit object.
  obj = {"#{'a'}": 1, b: 2}
  deepEqual obj, {a: 1, b: 2}
  obj = {a: 1, "#{'b'}": 2}
  deepEqual obj, {a: 1, b: 2}
  obj = {"#{'a'}": 1, "#{'b'}": 2}
  deepEqual obj, {a: 1, b: 2}

  # Commas after key with interpolation.
  obj = {"#{'a'}": yes,}
  eq obj.a, yes
  obj = {
    "#{'a'}": 1,
    "#{'b'}": 2,
    ### herecomment ###
    "#{'c'}": 3,
  }
  deepEqual obj, {a: 1, b: 2, c: 3}
  obj =
    "#{'a'}": 1,
    "#{'b'}": 2,
    ### herecomment ###
    "#{'c'}": 3,
  deepEqual obj, {a: 1, b: 2, c: 3}
  obj =
    "#{'a'}": 1,
    "#{'b'}": 2,
    ### herecomment ###
    "#{'c'}": 3, "#{'d'}": 4,
  deepEqual obj, {a: 1, b: 2, c: 3, d: 4}

  # Key with interpolation mixed with `@prop`.
  deepEqual (-> {@a, "#{'b'}": 2}).call(a: 1), {a: 1, b: 2}

  # Evaluate only once.
  count = 0
  b = -> count++; 'b'
  obj = {"#{b()}"}
  eq obj.b, 'b'
  eq count, 1

  # Evaluation order.
  arr = []
  obj =
    a: arr.push 1
    b: arr.push 2
    "#{'c'}": arr.push 3
    "#{'d'}": arr.push 4
    e: arr.push 5
    "#{'f'}": arr.push 6
    g: arr.push 7
  arrayEq arr, [1..7]
  deepEqual obj, {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7}

  # Object starting with dynamic key.
  obj =
    "#{'a'}": 1
    b: 2
  deepEqual obj, {a: 1, b: 2}

  # Comments in implicit object.
  obj =
    ### leading comment ###
    "#{'a'}": 1

    ### middle ###

    "#{'b'}": 2
    # regular comment
    'c': 3
    ### foo ###
    d: 4
    "#{'e'}": 5
  deepEqual obj, {a: 1, b: 2, c: 3, d: 4, e: 5}

  # Comments in explicit object.
  obj = {
    ### leading comment ###
    "#{'a'}": 1

    ### middle ###

    "#{'b'}": 2
    # regular comment
    'c': 3
    ### foo ###
    d: 4
    "#{'e'}": 5
  }
  deepEqual obj, {a: 1, b: 2, c: 3, d: 4, e: 5}

  # A more complicated case.
  obj = {
    "#{'interpolated'}":
      """
        #{ '''nested''' }
      """: 123: 456
  }
  deepEqual obj,
    interpolated:
      nested:
        123: 456

test "#4324: Shorthand after interpolated key", ->
  a = 2
  obj = {"#{1}": 1, a}
  eq 1, obj[1]
  eq 2, obj.a

test "#1263: Braceless object return", ->
  fn = ->
    return
      a: 1
      b: 2
      c: -> 3

  obj = fn()
  eq 1, obj.a
  eq 2, obj.b
  eq 3, obj.c()

</script>
<script type="text/x-coffeescript" class="test" id="operators">
# Operators
# ---------

# * Operators
# * Existential Operator (Binary)
# * Existential Operator (Unary)
# * Aliased Operators
# * [not] in/of
# * Chained Comparison

test "binary (2-ary) math operators do not require spaces", ->
  a = 1
  b = -1
  eq +1, a*-b
  eq -1, a*+b
  eq +1, a/-b
  eq -1, a/+b

test "operators should respect new lines as spaced", ->
  a = 123 +
  456
  eq 579, a

  b = "1#{2}3" +
  "456"
  eq '123456', b

test "multiple operators should space themselves", ->
  eq (+ +1), (- -1)

test "compound operators on successive lines", ->
  a = 1
  a +=
  1
  eq a, 2

test "bitwise operators", ->
  eq  2, (10 &   3)
  eq 11, (10 |   3)
  eq  9, (10 ^   3)
  eq 80, (10 <<  3)
  eq  1, (10 >>  3)
  eq  1, (10 >>> 3)
  num = 10; eq  2, (num &=   3)
  num = 10; eq 11, (num |=   3)
  num = 10; eq  9, (num ^=   3)
  num = 10; eq 80, (num <<=  3)
  num = 10; eq  1, (num >>=  3)
  num = 10; eq  1, (num >>>= 3)

test "`instanceof`", ->
  ok new String instanceof String
  ok new Boolean instanceof Boolean
  # `instanceof` supports negation by prefixing the operator with `not`
  ok new Number not instanceof String
  ok new Array not instanceof Boolean

test "use `::` operator on keywords `this` and `@`", ->
  nonce = {}
  obj =
    withAt:   -> @::prop
    withThis: -> this::prop
  obj.prototype = prop: nonce
  eq nonce, obj.withAt()
  eq nonce, obj.withThis()


# Existential Operator (Binary)

test "binary existential operator", ->
  nonce = {}

  b = a ? nonce
  eq nonce, b

  a = null
  b = undefined
  b = a ? nonce
  eq nonce, b

  a = false
  b = a ? nonce
  eq false, b

  a = 0
  b = a ? nonce
  eq 0, b

test "binary existential operator conditionally evaluates second operand", ->
  i = 1
  func = -> i -= 1
  result = func() ? func()
  eq result, 0

test "binary existential operator with negative number", ->
  a = null ? - 1
  eq -1, a


# Existential Operator (Unary)

test "postfix existential operator", ->
  ok (if nonexistent? then false else true)
  defined = true
  ok defined?
  defined = false
  ok defined?

test "postfix existential operator only evaluates its operand once", ->
  semaphore = 0
  fn = ->
    ok false if semaphore
    ++semaphore
  ok(if fn()? then true else false)

test "negated postfix existential operator", ->
  ok !nothing?.value

test "postfix existential operator on expressions", ->
  eq true, (1 or 0)?, true


# `is`,`isnt`,`==`,`!=`

test "`==` and `is` should be interchangeable", ->
  a = b = 1
  ok a is 1 and b == 1
  ok a == b
  ok a is b

test "`!=` and `isnt` should be interchangeable", ->
  a = 0
  b = 1
  ok a isnt 1 and b != 0
  ok a != b
  ok a isnt b


# [not] in/of

# - `in` should check if an array contains a value using `indexOf`
# - `of` should check if a property is defined on an object using `in`
test "in, of", ->
  arr = [1]
  ok 0 of arr
  ok 1 in arr
  # prefixing `not` to `in and `of` should negate them
  ok 1 not of arr
  ok 0 not in arr

test "`in` should be able to operate on an array literal", ->
  ok 2 in [0, 1, 2, 3]
  ok 4 not in [0, 1, 2, 3]
  arr = [0, 1, 2, 3]
  ok 2 in arr
  ok 4 not in arr
  # should cache the value used to test the array
  arr = [0]
  val = 0
  ok val++ in arr
  ok val++ not in arr
  val = 0
  ok val++ of arr
  ok val++ not of arr

test "`of` and `in` should be able to operate on instance variables", ->
  obj = {
    list: [2,3]
    in_list: (value) -> value in @list
    not_in_list: (value) -> value not in @list
    of_list: (value) -> value of @list
    not_of_list: (value) -> value not of @list
  }
  ok obj.in_list 3
  ok obj.not_in_list 1
  ok obj.of_list 0
  ok obj.not_of_list 2

test "#???: `in` with cache and `__indexOf` should work in argument lists", ->
  eq 1, [Object() in Array()].length

test "#737: `in` should have higher precedence than logical operators", ->
  eq 1, 1 in [1] and 1

test "#768: `in` should preserve evaluation order", ->
  share = 0
  a = -> share++ if share is 0
  b = -> share++ if share is 1
  c = -> share++ if share is 2
  ok a() not in [b(),c()]
  eq 3, share

test "#1099: empty array after `in` should compile to `false`", ->
  eq 1, [5 in []].length
  eq false, do -> return 0 in []

test "#1354: optimized `in` checks should not happen when splats are present", ->
  a = [6, 9]
  eq 9 in [3, a...], true

test "#1100: precedence in or-test compilation of `in`", ->
  ok 0 in [1 and 0]
  ok 0 in [1, 1 and 0]
  ok not (0 in [1, 0 or 1])

test "#1630: `in` should check `hasOwnProperty`", ->
  ok undefined not in length: 1

test "#1714: lexer bug with raw range `for` followed by `in`", ->
  0 for [1..2]
  ok not ('a' in ['b'])

  0 for [1..2]; ok not ('a' in ['b'])

  0 for [1..10] # comment ending
  ok not ('a' in ['b'])

  # lexer state (specifically @seenFor) should be reset before each compilation
  CoffeeScript.compile "0 for [1..2]"
  CoffeeScript.compile "'a' in ['b']"

test "#1099: statically determined `not in []` reporting incorrect result", ->
  ok 0 not in []

test "#1099: make sure expression tested gets evaluted when array is empty", ->
  a = 0
  (do -> a = 1) in []
  eq a, 1

# Chained Comparison

test "chainable operators", ->
  ok 100 > 10 > 1 > 0 > -1
  ok -1 < 0 < 1 < 10 < 100

test "`is` and `isnt` may be chained", ->
  ok true is not false is true is not false
  ok 0 is 0 isnt 1 is 1

test "different comparison operators (`>`,`<`,`is`,etc.) may be combined", ->
  ok 1 < 2 > 1
  ok 10 < 20 > 2+3 is 5

test "some chainable operators can be negated by `unless`", ->
  ok (true unless 0==10!=100)

test "operator precedence: `|` lower than `<`", ->
  eq 1, 1 | 2 < 3 < 4

test "preserve references", ->
  a = b = c = 1
  # `a == b <= c` should become `a === b && b <= c`
  # (this test does not seem to test for this)
  ok a == b <= c

test "chained operations should evaluate each value only once", ->
  a = 0
  ok 1 > a++ < 1

test "#891: incorrect inversion of chained comparisons", ->
  ok (true unless 0 > 1 > 2)
  ok (true unless (this.NaN = 0/0) < 0/0 < this.NaN)

test "#1234: Applying a splat to :: applies the splat to the wrong object", ->
  nonce = {}
  class C
    method: -> @nonce
    nonce: nonce

  arr = []
  eq nonce, C::method arr... # should be applied to `C::`

test "#1102: String literal prevents line continuation", ->
  eq "': '", '' +
     "': '"

test "#1703, ---x is invalid JS", ->
  x = 2
  eq (- --x), -1

test "Regression with implicit calls against an indented assignment", ->
  eq 1, a =
    1

  eq a, 1

test "#2155 ... conditional assignment to a closure", ->
  x = null
  func = -> x ?= (-> if true then 'hi')
  func()
  eq x(), 'hi'

test "#2197: Existential existential double trouble", ->
  counter = 0
  func = -> counter++
  func()? ? 100
  eq counter, 1

test "#2567: Optimization of negated existential produces correct result", ->
  a = 1
  ok !(!a?)
  ok !b?

test "#2508: Existential access of the prototype", ->
  eq NonExistent?::nothing, undefined
  ok Object?::toString

test "power operator", ->
  eq 27, 3 ** 3

test "power operator has higher precedence than other maths operators", ->
  eq 55, 1 + 3 ** 3 * 2
  eq -4, -2 ** 2
  eq false, !2 ** 2
  eq 0, (!2) ** 2
  eq -2, ~1 ** 5

test "power operator is right associative", ->
  eq 2, 2 ** 1 ** 3

test "power operator compound assignment", ->
  a = 2
  a **= 3
  eq 8, a

test "floor division operator", ->
  eq 2, 7 // 3
  eq -3, -7 // 3
  eq NaN, 0 // 0

test "floor division operator compound assignment", ->
  a = 7
  a //= 1 + 1
  eq 3, a

test "modulo operator", ->
  check = (a, b, expected) ->
    eq expected, a %% b, "expected #{a} %%%% #{b} to be #{expected}"
  check 0, 1, 0
  check 0, -1, -0
  check 1, 0, NaN
  check 1, 2, 1
  check 1, -2, -1
  check 1, 3, 1
  check 2, 3, 2
  check 3, 3, 0
  check 4, 3, 1
  check -1, 3, 2
  check -2, 3, 1
  check -3, 3, 0
  check -4, 3, 2
  check 5.5, 2.5, 0.5
  check -5.5, 2.5, 2.0

test "modulo operator compound assignment", ->
  a = -2
  a %%= 5
  eq 3, a

test "modulo operator converts arguments to numbers", ->
  eq 1, 1 %% '42'
  eq 1, '1' %% 42
  eq 1, '1' %% '42'

test "#3361: Modulo operator coerces right operand once", ->
  count = 0
  res = 42 %% valueOf: -> count += 1
  eq 1, count
  eq 0, res

test "#3363: Modulo operator coercing order", ->
  count = 2
  a = valueOf: -> count *= 2
  b = valueOf: -> count += 1
  eq 4, a %% b
  eq 5, count

test "#3598: Unary + and - coerce the operand once when it is an identifier", ->
  # Unary + and - do not generate `_ref`s when the operand is a number, for
  # readability. To make sure that they do when the operand is an identifier,
  # test that they are consistent with another unary operator as well as another
  # complex expression.
  # Tip: Making one of the tests temporarily fail lets you easily inspect the
  # compiled JavaScript.

  assertOneCoercion = (fn) ->
    count = 0
    value = valueOf: -> count++; 1
    fn value
    eq 1, count

  eq 1, 1 ? 0
  eq 1, +1 ? 0
  eq -1, -1 ? 0
  assertOneCoercion (a) ->
    eq 1, +a ? 0
  assertOneCoercion (a) ->
    eq -1, -a ? 0
  assertOneCoercion (a) ->
    eq -2, ~a ? 0
  assertOneCoercion (a) ->
    eq 0.5, a / 2 ? 0

  ok -2 <= 1 < 2
  ok -2 <= +1 < 2
  ok -2 <= -1 < 2
  assertOneCoercion (a) ->
    ok -2 <= +a < 2
  assertOneCoercion (a) ->
    ok -2 <= -a < 2
  assertOneCoercion (a) ->
    ok -2 <= ~a < 2
  assertOneCoercion (a) ->
    ok -2 <= a / 2 < 2

  arrayEq [0], (n for n in [0] by 1)
  arrayEq [0], (n for n in [0] by +1)
  arrayEq [0], (n for n in [0] by -1)
  assertOneCoercion (a) ->
    arrayEq [0], (n for n in [0] by +a)
  assertOneCoercion (a) ->
    arrayEq [0], (n for n in [0] by -a)
  assertOneCoercion (a) ->
    arrayEq [0], (n for n in [0] by ~a)
  assertOneCoercion (a) ->
    arrayEq [0], (n for n in [0] by a * 2 / 2)

  ok 1 in [0, 1]
  ok +1 in [0, 1]
  ok -1 in [0, -1]
  assertOneCoercion (a) ->
    ok +a in [0, 1]
  assertOneCoercion (a) ->
    ok -a in [0, -1]
  assertOneCoercion (a) ->
    ok ~a in [0, -2]
  assertOneCoercion (a) ->
    ok a / 2 in [0, 0.5]

</script>
<script type="text/x-coffeescript" class="test" id="option_parser">
# Option Parser
# -------------

# TODO: refactor option parser tests

# Ensure that the OptionParser handles arguments correctly.
return unless require?
{OptionParser} = require './../lib/coffee-script/optparse'

opt = new OptionParser [
  ['-r', '--required [DIR]',  'desc required']
  ['-o', '--optional',        'desc optional']
  ['-l', '--list [FILES*]',   'desc list']
]

test "basic arguments", ->
  args = ['one', 'two', 'three', '-r', 'dir']
  result = opt.parse args
  arrayEq args, result.arguments
  eq undefined, result.required

test "boolean and parameterised options", ->
  result = opt.parse ['--optional', '-r', 'folder', 'one', 'two']
  ok result.optional
  eq 'folder', result.required
  arrayEq ['one', 'two'], result.arguments

test "list options", ->
  result = opt.parse ['-l', 'one.txt', '-l', 'two.txt', 'three']
  arrayEq ['one.txt', 'two.txt'], result.list
  arrayEq ['three'], result.arguments

test "-- and interesting combinations", ->
  result = opt.parse ['-o','-r','a','-r','b','-o','--','-a','b','--c','d']
  arrayEq ['-a', 'b', '--c', 'd'], result.arguments
  ok result.optional
  eq 'b', result.required

  args = ['--','-o','a','-r','c','-o','--','-a','arg0','-b','arg1']
  result = opt.parse args
  eq undefined, result.optional
  eq undefined, result.required
  arrayEq args[1..], result.arguments

</script>
<script type="text/x-coffeescript" class="test" id="parser">
# Parser
# ---------

test "operator precedence for logical operators", ->
  source = '''
    a or b and c
  '''
  block = CoffeeScript.nodes source
  [expression] = block.expressions
  eq expression.first.base.value, 'a'
  eq expression.operator, '||'
  eq expression.second.first.base.value, 'b'
  eq expression.second.operator, '&&'
  eq expression.second.second.base.value, 'c'

test "operator precedence for bitwise operators", ->
  source = '''
    a | b ^ c & d
  '''
  block = CoffeeScript.nodes source
  [expression] = block.expressions
  eq expression.first.base.value, 'a'
  eq expression.operator, '|'
  eq expression.second.first.base.value, 'b'
  eq expression.second.operator, '^'
  eq expression.second.second.first.base.value, 'c'
  eq expression.second.second.operator, '&'
  eq expression.second.second.second.base.value, 'd'

test "operator precedence for binary ? operator", ->
  source = '''
     a ? b and c
  '''
  block = CoffeeScript.nodes source
  [expression] = block.expressions
  eq expression.first.base.value, 'a'
  eq expression.operator, '?'
  eq expression.second.first.base.value, 'b'
  eq expression.second.operator, '&&'
  eq expression.second.second.base.value, 'c'

test "new calls have a range including the new", ->
  source = '''
    a = new B().c(d)
  '''
  block = CoffeeScript.nodes source

  assertColumnRange = (node, firstColumn, lastColumn) ->
    eq node.locationData.first_line, 0
    eq node.locationData.first_column, firstColumn
    eq node.locationData.last_line, 0
    eq node.locationData.last_column, lastColumn

  [assign] = block.expressions
  outerCall = assign.value
  innerValue = outerCall.variable
  innerCall = innerValue.base

  assertColumnRange assign, 0, 15
  assertColumnRange outerCall, 4, 15
  assertColumnRange innerValue, 4, 12
  assertColumnRange innerCall, 4, 10

test "location data is properly set for nested `new`", ->
  source = '''
    new new A()()
  '''
  block = CoffeeScript.nodes source

  assertColumnRange = (node, firstColumn, lastColumn) ->
    eq node.locationData.first_line, 0
    eq node.locationData.first_column, firstColumn
    eq node.locationData.last_line, 0
    eq node.locationData.last_column, lastColumn

  [outerCall] = block.expressions
  innerCall = outerCall.variable

  assertColumnRange outerCall, 0, 12
  assertColumnRange innerCall, 4, 10

</script>
<script type="text/x-coffeescript" class="test" id="ranges">
# Range Literals
# --------------

# TODO: add indexing and method invocation tests: [1..4][0] is 1, [0...3].toString()

# shared array
shared = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

test "basic inclusive ranges", ->
  arrayEq [1, 2, 3] , [1..3]
  arrayEq [0, 1, 2] , [0..2]
  arrayEq [0, 1]    , [0..1]
  arrayEq [0]       , [0..0]
  arrayEq [-1]      , [-1..-1]
  arrayEq [-1, 0]   , [-1..0]
  arrayEq [-1, 0, 1], [-1..1]

test "basic exclusive ranges", ->
  arrayEq [1, 2, 3] , [1...4]
  arrayEq [0, 1, 2] , [0...3]
  arrayEq [0, 1]    , [0...2]
  arrayEq [0]       , [0...1]
  arrayEq [-1]      , [-1...0]
  arrayEq [-1, 0]   , [-1...1]
  arrayEq [-1, 0, 1], [-1...2]

  arrayEq [], [1...1]
  arrayEq [], [0...0]
  arrayEq [], [-1...-1]

test "downward ranges", ->
  arrayEq shared, [9..0].reverse()
  arrayEq [5, 4, 3, 2] , [5..2]
  arrayEq [2, 1, 0, -1], [2..-1]

  arrayEq [3, 2, 1]  , [3..1]
  arrayEq [2, 1, 0]  , [2..0]
  arrayEq [1, 0]     , [1..0]
  arrayEq [0]        , [0..0]
  arrayEq [-1]       , [-1..-1]
  arrayEq [0, -1]    , [0..-1]
  arrayEq [1, 0, -1] , [1..-1]
  arrayEq [0, -1, -2], [0..-2]

  arrayEq [4, 3, 2], [4...1]
  arrayEq [3, 2, 1], [3...0]
  arrayEq [2, 1]   , [2...0]
  arrayEq [1]      , [1...0]
  arrayEq []       , [0...0]
  arrayEq []       , [-1...-1]
  arrayEq [0]      , [0...-1]
  arrayEq [0, -1]  , [0...-2]
  arrayEq [1, 0]   , [1...-1]
  arrayEq [2, 1, 0], [2...-1]

test "ranges with variables as enpoints", ->
  [a, b] = [1, 3]
  arrayEq [1, 2, 3], [a..b]
  arrayEq [1, 2]   , [a...b]
  b = -2
  arrayEq [1, 0, -1, -2], [a..b]
  arrayEq [1, 0, -1]    , [a...b]

test "ranges with expressions as endpoints", ->
  [a, b] = [1, 3]
  arrayEq [2, 3, 4, 5, 6], [(a+1)..2*b]
  arrayEq [2, 3, 4, 5]   , [(a+1)...2*b]

test "large ranges are generated with looping constructs", ->
  down = [99..0]
  eq 100, (len = down.length)
  eq   0, down[len - 1]

  up = [0...100]
  eq 100, (len = up.length)
  eq  99, up[len - 1]

test "for-from loops over ranges", ->
  array1 = []
  for x from [20..30]
    array1.push(x)
    break if x is 25
  arrayEq array1, [20, 21, 22, 23, 24, 25]

test "for-from comprehensions over ranges", ->
  array1 = (x + 10 for x from [20..25])
  ok array1.join(' ') is '30 31 32 33 34 35'

  array2 = (x for x from [20..30] when x %% 2 == 0)
  ok array2.join(' ') is '20 22 24 26 28 30'

test "#1012 slices with arguments object", ->
  expected = [0..9]
  argsAtStart = (-> [arguments[0]..9]) 0
  arrayEq expected, argsAtStart
  argsAtEnd = (-> [0..arguments[0]]) 9
  arrayEq expected, argsAtEnd
  argsAtBoth = (-> [arguments[0]..arguments[1]]) 0, 9
  arrayEq expected, argsAtBoth

test "#1409: creating large ranges outside of a function body", ->
  CoffeeScript.eval '[0..100]'

</script>
<script type="text/x-coffeescript" class="test" id="regexps">
# Regular Expression Literals
# ---------------------------

# TODO: add method invocation tests: /regex/.toString()

# * Regexen
# * Heregexen

test "basic regular expression literals", ->
  ok 'a'.match(/a/)
  ok 'a'.match /a/
  ok 'a'.match(/a/g)
  ok 'a'.match /a/g

test "division is not confused for a regular expression", ->
  # Any spacing around the slash is allowed when it cannot be a regex.
  eq 2, 4 / 2 / 1
  eq 2, 4/2/1
  eq 2, 4/ 2 / 1
  eq 2, 4 /2 / 1
  eq 2, 4 / 2/ 1
  eq 2, 4 / 2 /1
  eq 2, 4 /2/ 1

  a = (regex) -> regex.test 'a b c'
  a.valueOf = -> 4
  b = 2
  g = 1

  eq 2, a / b/g
  eq 2, a/ b/g
  eq 2, a / b/ g
  eq 2, a	/	b/g # Tabs.
  eq 2, a / b/g # Non-breaking spaces.
  eq true, a /b/g
  # Use parentheses to disambiguate.
  eq true, a(/ b/g)
  eq true, a(/ b/)
  eq true, a (/ b/)
  # Escape to disambiguate.
  eq true, a /\ b/g
  eq false, a	/\	b/g
  eq true, a /\ b/

  obj = method: -> 2
  two = 2
  eq 2, (obj.method()/two + obj.method()/two)

  i = 1
  eq 2, (4)/2/i
  eq 1, i/i/i

  a = ''
  a += ' ' until /   /.test a
  eq a, '   '

  a = if /=/.test '=' then yes else no
  eq a, yes

  a = if !/=/.test '=' then yes else no
  eq a, no

  #3182:
  match = 'foo=bar'.match /=/
  eq match[0], '='

  #3410:
  ok ' '.match(/ /)[0] is ' '


test "division vs regex after a callable token", ->
  b = 2
  g = 1
  r = (r) -> r.test 'b'

  a = 4
  eq 2, a / b/g
  eq 2, a/b/g
  eq 2, a/ b/g
  eq true, r /b/g
  eq 2, (1 + 3) / b/g
  eq 2, (1 + 3)/b/g
  eq 2, (1 + 3)/ b/g
  eq true, (r) /b/g
  eq 2, [4][0] / b/g
  eq 2, [4][0]/b/g
  eq 2, [4][0]/ b/g
  eq true, [r][0] /b/g
  eq 0.5, 4? / b/g
  eq 0.5, 4?/b/g
  eq 0.5, 4?/ b/g
  eq true, r? /b/g
  (->
    eq 2, @ / b/g
    eq 2, @/b/g
    eq 2, @/ b/g
  ).call 4
  (->
    eq true, @ /b/g
  ).call r
  (->
    eq 2, this / b/g
    eq 2, this/b/g
    eq 2, this/ b/g
  ).call 4
  (->
    eq true, this /b/g
  ).call r
  class A
    p: (regex) -> if regex then r regex else 4
  class B extends A
    p: ->
      eq 2, super / b/g
      eq 2, super/b/g
      eq 2, super/ b/g
      eq true, super /b/g
  new B().p()

test "always division and never regex after some tokens", ->
  b = 2
  g = 1

  eq 2, 4 / b/g
  eq 2, 4/b/g
  eq 2, 4/ b/g
  eq 2, 4 /b/g
  eq 2, "4" / b/g
  eq 2, "4"/b/g
  eq 2, "4"/ b/g
  eq 2, "4" /b/g
  eq 20, "4#{0}" / b/g
  eq 20, "4#{0}"/b/g
  eq 20, "4#{0}"/ b/g
  eq 20, "4#{0}" /b/g
  ok isNaN /a/ / b/g
  ok isNaN /a/i / b/g
  ok isNaN /a//b/g
  ok isNaN /a/i/b/g
  ok isNaN /a// b/g
  ok isNaN /a/i/ b/g
  ok isNaN /a/ /b/g
  ok isNaN /a/i /b/g
  eq 0.5, true / b/g
  eq 0.5, true/b/g
  eq 0.5, true/ b/g
  eq 0.5, true /b/g
  eq 0, false / b/g
  eq 0, false/b/g
  eq 0, false/ b/g
  eq 0, false /b/g
  eq 0, null / b/g
  eq 0, null/b/g
  eq 0, null/ b/g
  eq 0, null /b/g
  ok isNaN undefined / b/g
  ok isNaN undefined/b/g
  ok isNaN undefined/ b/g
  ok isNaN undefined /b/g
  ok isNaN {a: 4} / b/g
  ok isNaN {a: 4}/b/g
  ok isNaN {a: 4}/ b/g
  ok isNaN {a: 4} /b/g
  o = prototype: 4
  eq 2, o:: / b/g
  eq 2, o::/b/g
  eq 2, o::/ b/g
  eq 2, o:: /b/g
  i = 4
  eq 2.0, i++ / b/g
  eq 2.5, i++/b/g
  eq 3.0, i++/ b/g
  eq 3.5, i++ /b/g
  eq 4.0, i-- / b/g
  eq 3.5, i--/b/g
  eq 3.0, i--/ b/g
  eq 2.5, i-- /b/g

test "compound division vs regex", ->
  c = 4
  i = 2

  a = 10
  b = a /= c / i
  eq a, 5

  a = 10
  b = a /= c /i
  eq a, 5

  a = 10
  b = a	/=	c /i # Tabs.
  eq a, 5

  a = 10
  b = a /= c /i # Non-breaking spaces.
  eq a, 5

  a = 10
  b = a/= c /i
  eq a, 5

  a = 10
  b = a/=c/i
  eq a, 5

  a = (regex) -> regex.test '=C '
  b = a /=c /i
  eq b, true

  a = (regex) -> regex.test '= C '
  # Use parentheses to disambiguate.
  b = a(/= c /i)
  eq b, true
  b = a(/= c /)
  eq b, false
  b = a (/= c /)
  eq b, false
  # Escape to disambiguate.
  b = a /\= c /i
  eq b, true
  b = a /\= c /
  eq b, false

test "#764: regular expressions should be indexable", ->
  eq /0/['source'], ///#{0}///['source']

test "#584: slashes are allowed unescaped in character classes", ->
  ok /^a\/[/]b$/.test 'a//b'

test "does not allow to escape newlines", ->
  throws -> CoffeeScript.compile '/a\\\nb/'


# Heregexe(n|s)

test "a heregex will ignore whitespace and comments", ->
  eq /^I'm\x20+[a]\s+Heregex?\/\/\//gim + '', ///
    ^ I'm \x20+ [a] \s+
    Heregex? / // # or not
  ///gim + ''

test "an empty heregex will compile to an empty, non-capturing group", ->
  eq /(?:)/ + '', ///  /// + ''
  eq /(?:)/ + '', ////// + ''

test "heregex starting with slashes", ->
  ok /////a/\////.test ' //a// '

test '#2388: `///` in heregex interpolations', ->
  ok ///a#{///b///}c///.test ' /a/b/c/ '
  ws = ' \t'
  scan = (regex) -> regex.exec('\t  foo')[0]
  eq '/\t  /', /// #{scan /// [#{ws}]* ///} /// + ''

test "regexes are not callable", ->
  throws -> CoffeeScript.compile '/a/()'
  throws -> CoffeeScript.compile '///a#{b}///()'
  throws -> CoffeeScript.compile '/a/ 1'
  throws -> CoffeeScript.compile '///a#{b}/// 1'
  throws -> CoffeeScript.compile '''
    /a/
       k: v
  '''
  throws -> CoffeeScript.compile '''
    ///a#{b}///
       k: v
  '''

test "backreferences", ->
  ok /(a)(b)\2\1/.test 'abba'

test "#3795: Escape otherwise invalid characters", ->
  ok (/ /).test '\u2028'
  ok (/ /).test '\u2029'
  ok ///\ ///.test '\u2028'
  ok ///\ ///.test '\u2029'
  ok ///a b///.test 'ab' # The space is U+2028.
  ok ///a b///.test 'ab' # The space is U+2029.
  ok ///\0
      1///.test '\x001'

  a = 'a'
  ok ///#{a} b///.test 'ab' # The space is U+2028.
  ok ///#{a} b///.test 'ab' # The space is U+2029.
  ok ///#{a}\ ///.test 'a\u2028'
  ok ///#{a}\ ///.test 'a\u2029'
  ok ///#{a}\0
      1///.test 'a\x001'

test "#4248: Unicode code point escapes", ->
  # Support for the `u` flag in regexes was added in Node 6.
  return if new RegExp().unicode is undefined
  ok /a\u{1ab}c/u.test 'a\u01abc'
  ok ///#{ 'a' }\u{000001ab}c///u.test 'a\u{1ab}c'
  ok ///a\u{000001ab}c///u.test 'a\u{1ab}c'
  ok /a\u{12345}c/u.test 'a\ud808\udf45c'

  # and now without u flag
  ok /a\u{1ab}c/.test 'a\u01abc'
  ok ///#{ 'a' }\u{000001ab}c///.test 'a\u{1ab}c'
  ok ///a\u{000001ab}c///.test 'a\u{1ab}c'
  ok /a\u{12345}c/.test 'a\ud808\udf45c'

  # rewrite code point escapes
  input = """
    /\\u{bcdef}\\u{abc}/u
    """
  output = """
    /\\udab3\\uddef\\u0abc/u;
  """
  eq toJS(input), output

  input = """
    ///#{ 'a' }\\u{bcdef}///
    """
  output = """
    /a\\udab3\\uddef/;
  """
  eq toJS(input), output

</script>
<script type="text/x-coffeescript" class="test" id="repl">
return if global.testingBrowser

os = require 'os'
fs = require 'fs'
path = require 'path'

# REPL
# ----
Stream = require 'stream'

class MockInputStream extends Stream
  constructor: ->
    @readable = true

  resume: ->

  emitLine: (val) ->
    @emit 'data', new Buffer("#{val}\n")

class MockOutputStream extends Stream
  constructor: ->
    @writable = true
    @written = []

  write: (data) ->
    #console.log 'output write', arguments
    @written.push data

  lastWrite: (fromEnd = -1) ->
    @written[@written.length - 1 + fromEnd].replace /\r?\n$/, ''

# Create a dummy history file
historyFile = path.join os.tmpdir(), '.coffee_history_test'
fs.writeFileSync historyFile, '1 + 2\n'

testRepl = (desc, fn) ->
  input = new MockInputStream
  output = new MockOutputStream
  repl = Repl.start {input, output, historyFile}
  test desc, -> fn input, output, repl

ctrlV = { ctrl: true, name: 'v'}


testRepl 'reads history file', (input, output, repl) ->
  input.emitLine repl.rli.history[0]
  eq '3', output.lastWrite()

testRepl "starts with coffee prompt", (input, output) ->
  eq 'coffee> ', output.lastWrite(0)

testRepl "writes eval to output", (input, output) ->
  input.emitLine '1+1'
  eq '2', output.lastWrite()

testRepl "comments are ignored", (input, output) ->
  input.emitLine '1 + 1 #foo'
  eq '2', output.lastWrite()

testRepl "output in inspect mode", (input, output) ->
  input.emitLine '"1 + 1\\n"'
  eq "'1 + 1\\n'", output.lastWrite()

testRepl "variables are saved", (input, output) ->
  input.emitLine "foo = 'foo'"
  input.emitLine 'foobar = "#{foo}bar"'
  eq "'foobar'", output.lastWrite()

testRepl "empty command evaluates to undefined", (input, output) ->
  # A regression fixed in Node 5.11.0 broke the handling of pressing enter in
  # the Node REPL; see https://github.com/nodejs/node/pull/6090 and
  # https://github.com/jashkenas/coffeescript/issues/4502.
  # Just skip this test for versions of Node < 6.
  return if parseInt(process.versions.node.split('.')[0], 10) < 6
  input.emitLine ''
  eq 'undefined', output.lastWrite()

testRepl "ctrl-v toggles multiline prompt", (input, output) ->
  input.emit 'keypress', null, ctrlV
  eq '------> ', output.lastWrite(0)
  input.emit 'keypress', null, ctrlV
  eq 'coffee> ', output.lastWrite(0)

testRepl "multiline continuation changes prompt", (input, output) ->
  input.emit 'keypress', null, ctrlV
  input.emitLine ''
  eq '....... ', output.lastWrite(0)

testRepl "evaluates multiline", (input, output) ->
  # Stubs. Could assert on their use.
  output.cursorTo = (pos) ->
  output.clearLine = ->

  input.emit 'keypress', null, ctrlV
  input.emitLine 'do ->'
  input.emitLine '  1 + 1'
  input.emit 'keypress', null, ctrlV
  eq '2', output.lastWrite()

testRepl "variables in scope are preserved", (input, output) ->
  input.emitLine 'a = 1'
  input.emitLine 'do -> a = 2'
  input.emitLine 'a'
  eq '2', output.lastWrite()

testRepl "existential assignment of previously declared variable", (input, output) ->
  input.emitLine 'a = null'
  input.emitLine 'a ?= 42'
  eq '42', output.lastWrite()

testRepl "keeps running after runtime error", (input, output) ->
  input.emitLine 'a = b'
  input.emitLine 'a'
  eq 'undefined', output.lastWrite()

process.on 'exit', ->
  try
    fs.unlinkSync historyFile
  catch exception # Already deleted, nothing else to do.

</script>
<script type="text/x-coffeescript" class="test" id="scope">
# Scope
# -----

# * Variable Safety
# * Variable Shadowing
# * Auto-closure (`do`)
# * Global Scope Leaks

test "reference `arguments` inside of functions", ->
  sumOfArgs = ->
    sum = (a,b) -> a + b
    sum = 0
    sum += num for num in arguments
    sum
  eq 10, sumOfArgs(0, 1, 2, 3, 4)

test "assignment to an Object.prototype-named variable should not leak to outer scope", ->
  # FIXME: fails on IE
  (->
    constructor = 'word'
  )()
  ok constructor isnt 'word'

test "siblings of splat parameters shouldn't leak to surrounding scope", ->
  x = 10
  oops = (x, args...) ->
  oops(20, 1, 2, 3)
  eq x, 10

test "catch statements should introduce their argument to scope", ->
  try throw ''
  catch e
    do -> e = 5
    eq 5, e

test "loop variable should be accessible after for-of loop", ->
  d = (x for x of {1:'a',2:'b'})
  ok x in ['1','2']

test "loop variable should be accessible after for-in loop", ->
  d = (x for x in [1,2])
  eq x, 2

test "loop variable should be accessible after for-from loop", ->
  d = (x for x from [1,2])
  eq x, 2

class Array then slice: fail # needs to be global
class Object then hasOwnProperty: fail
test "#1973: redefining Array/Object constructors shouldn't confuse __X helpers", ->
  arr = [1..4]
  arrayEq [3, 4], arr[2..]
  obj = {arr}
  for own k of obj
    eq arr, obj[k]

test "#2255: global leak with splatted @-params", ->
  ok not x?
  arrayEq [0], ((@x...) -> @x).call {}, 0
  ok not x?

test "#1183: super + fat arrows", ->
  dolater = (cb) -> cb()

  class A
  	constructor: ->
  		@_i = 0
  	foo : (cb) ->
  		dolater =>
  			@_i += 1
  			cb()

  class B extends A
  	constructor : ->
  		super
  	foo : (cb) ->
  		dolater =>
  			dolater =>
  				@_i += 2
  				super cb

  b = new B
  b.foo => eq b._i, 3

test "#1183: super + wrap", ->
  class A
    m : -> 10

  class B extends A
    constructor : -> super

  B::m = -> r = try super()

  eq (new B).m(), 10

test "#1183: super + closures", ->
  class A
    constructor: ->
      @i = 10
    foo : -> @i

  class B extends A
    foo : ->
      ret = switch 1
        when 0 then 0
        when 1 then super()
      ret
  eq (new B).foo(), 10

test "#2331: bound super regression", ->
  class A
    @value = 'A'
    method: -> @constructor.value

  class B extends A
    method: => super

  eq (new B).method(), 'A'

test "#3259: leak with @-params within destructured parameters", ->
  fn = ({@foo}, [@bar], [{@baz}]) ->
    foo = bar = baz = false

  fn.call {}, {foo: 'foo'}, ['bar'], [{baz: 'baz'}]

  eq 'undefined', typeof foo
  eq 'undefined', typeof bar
  eq 'undefined', typeof baz

</script>
<script type="text/x-coffeescript" class="test" id="slicing_and_splicing">
# Slicing and Splicing
# --------------------

# * Slicing
# * Splicing

# shared array
shared = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# Slicing

test "basic slicing", ->
  arrayEq [7, 8, 9]   , shared[7..9]
  arrayEq [2, 3]      , shared[2...4]
  arrayEq [2, 3, 4, 5], shared[2...6]

test "slicing with variables as endpoints", ->
  [a, b] = [1, 4]
  arrayEq [1, 2, 3, 4], shared[a..b]
  arrayEq [1, 2, 3]   , shared[a...b]

test "slicing with expressions as endpoints", ->
  [a, b] = [1, 3]
  arrayEq [2, 3, 4, 5, 6], shared[(a+1)..2*b]
  arrayEq [2, 3, 4, 5]   , shared[a+1...(2*b)]

test "unbounded slicing", ->
  arrayEq [7, 8, 9]   , shared[7..]
  arrayEq [8, 9]      , shared[-2..]
  arrayEq [9]         , shared[-1...]
  arrayEq [0, 1, 2]   , shared[...3]
  arrayEq [0, 1, 2, 3], shared[..-7]

  arrayEq shared      , shared[..-1]
  arrayEq shared[0..8], shared[...-1]

  for a in [-shared.length..shared.length]
    arrayEq shared[a..] , shared[a...]
  for a in [-shared.length+1...shared.length]
    arrayEq shared[..a][...-1] , shared[...a]

  arrayEq [1, 2, 3], [1, 2, 3][..]

test "#930, #835, #831, #746 #624: inclusive slices to -1 should slice to end", ->
  arrayEq shared, shared[0..-1]
  arrayEq shared, shared[..-1]
  arrayEq shared.slice(1,shared.length), shared[1..-1]

test "string slicing", ->
  str = "abcdefghijklmnopqrstuvwxyz"
  ok str[1...1] is ""
  ok str[1..1] is "b"
  ok str[1...5] is "bcde"
  ok str[0..4] is "abcde"
  ok str[-5..] is "vwxyz"

test "#1722: operator precedence in unbounded slice compilation", ->
  list = [0..9]
  n = 2 # some truthy number in `list`
  arrayEq [0..n], list[..n]
  arrayEq [0..n], list[..n or 0]
  arrayEq [0..n], list[..if n then n else 0]

test "#2349: inclusive slicing to numeric strings", ->
  arrayEq [0, 1], [0..10][.."1"]


# Splicing

test "basic splicing", ->
  ary = [0..9]
  ary[5..9] = [0, 0, 0]
  arrayEq [0, 1, 2, 3, 4, 0, 0, 0], ary

  ary = [0..9]
  ary[2...8] = []
  arrayEq [0, 1, 8, 9], ary

test "unbounded splicing", ->
  ary = [0..9]
  ary[3..] = [9, 8, 7]
  arrayEq [0, 1, 2, 9, 8, 7]. ary

  ary[...3] = [7, 8, 9]
  arrayEq [7, 8, 9, 9, 8, 7], ary

  ary[..] = [1, 2, 3]
  arrayEq [1, 2, 3], ary

test "splicing with variables as endpoints", ->
  [a, b] = [1, 8]

  ary = [0..9]
  ary[a..b] = [2, 3]
  arrayEq [0, 2, 3, 9], ary

  ary = [0..9]
  ary[a...b] = [5]
  arrayEq [0, 5, 8, 9], ary

test "splicing with expressions as endpoints", ->
  [a, b] = [1, 3]

  ary = [0..9]
  ary[ a+1 .. 2*b+1 ] = [4]
  arrayEq [0, 1, 4, 8, 9], ary

  ary = [0..9]
  ary[a+1...2*b+1] = [4]
  arrayEq [0, 1, 4, 7, 8, 9], ary

test "splicing to the end, against a one-time function", ->
  ary = null
  fn = ->
    if ary
      throw 'err'
    else
      ary = [1, 2, 3]

  fn()[0..] = 1

  arrayEq ary, [1]

test "the return value of a splice literal should be the RHS", ->
  ary = [0, 0, 0]
  eq (ary[0..1] = 2), 2

  ary = [0, 0, 0]
  eq (ary[0..] = 3), 3

  arrayEq [ary[0..0] = 0], [0]

test "#1723: operator precedence in unbounded splice compilation", ->
  n = 4 # some truthy number in `list`

  list = [0..9]
  list[..n] = n
  arrayEq [n..9], list

  list = [0..9]
  list[..n or 0] = n
  arrayEq [n..9], list

  list = [0..9]
  list[..if n then n else 0] = n
  arrayEq [n..9], list

test "#2953: methods on endpoints in assignment from array splice literal", ->
  list = [0..9]

  Number.prototype.same = -> this
  list[1.same()...9.same()] = 5
  delete Number.prototype.same

  arrayEq [0, 5, 9], list

</script>
<script type="text/x-coffeescript" class="test" id="soaks">
# Soaks
# -----

# * Soaked Property Access
# * Soaked Method Invocation
# * Soaked Function Invocation


# Soaked Property Access

test "soaked property access", ->
  nonce = {}
  obj = a: b: nonce
  eq nonce    , obj?.a.b
  eq nonce    , obj?['a'].b
  eq nonce    , obj.a?.b
  eq nonce    , obj?.a?['b']
  eq undefined, obj?.a?.non?.existent?.property

test "soaked property access caches method calls", ->
  nonce ={}
  obj = fn: -> a: nonce
  eq nonce    , obj.fn()?.a
  eq undefined, obj.fn()?.b

test "soaked property access caching", ->
  nonce = {}
  counter = 0
  fn = ->
    counter++
    'self'
  obj =
    self: -> @
    prop: nonce
  eq nonce, obj[fn()]()[fn()]()[fn()]()?.prop
  eq 3, counter

test "method calls on soaked methods", ->
  nonce = {}
  obj = null
  eq undefined, obj?.a().b()
  obj = a: -> b: -> nonce
  eq nonce    , obj?.a().b()

test "postfix existential operator mixes well with soaked property accesses", ->
  eq false, nonexistent?.property?

test "function invocation with soaked property access", ->
  id = (_) -> _
  eq undefined, id nonexistent?.method()

test "if-to-ternary should safely parenthesize soaked property accesses", ->
  ok (if nonexistent?.property then false else true)

test "#726: don't check for a property on a conditionally-referenced nonexistent thing", ->
  eq undefined, nonexistent?[Date()]

test "#756: conditional assignment edge cases", ->
  # TODO: improve this test
  a = null
  ok isNaN      a?.b.c +  1
  eq undefined, a?.b.c += 1
  eq undefined, ++a?.b.c
  eq undefined, delete a?.b.c

test "operations on soaked properties", ->
  # TODO: improve this test
  a = b: {c: 0}
  eq 1,   a?.b.c +  1
  eq 1,   a?.b.c += 1
  eq 2,   ++a?.b.c
  eq yes, delete a?.b.c


# Soaked Method Invocation

test "soaked method invocation", ->
  nonce = {}
  counter = 0
  obj =
    self: -> @
    increment: -> counter++; @
  eq obj      , obj.self?()
  eq undefined, obj.method?()
  eq nonce    , obj.self?().property = nonce
  eq undefined, obj.method?().property = nonce
  eq obj      , obj.increment().increment().self?()
  eq 2        , counter

test "#733: conditional assignments", ->
  a = b: {c: null}
  eq a.b?.c?(), undefined
  a.b?.c or= (it) -> it
  eq a.b?.c?(1), 1
  eq a.b?.c?([2, 3]...), 2


# Soaked Function Invocation

test "soaked function invocation", ->
  nonce = {}
  id = (_) -> _
  eq nonce    , id?(nonce)
  eq nonce    , (id? nonce)
  eq undefined, nonexistent?(nonce)
  eq undefined, (nonexistent? nonce)

test "soaked function invocation with generated functions", ->
  nonce = {}
  id = (_) -> _
  maybe = (fn, arg) -> if typeof fn is 'function' then () -> fn(arg)
  eq maybe(id, nonce)?(), nonce
  eq (maybe id, nonce)?(), nonce
  eq (maybe false, nonce)?(), undefined

test "soaked constructor invocation", ->
  eq 42       , +new Number? 42
  eq undefined,  new Other?  42

test "soaked constructor invocations with caching and property access", ->
  semaphore = 0
  nonce = {}
  class C
    constructor: ->
      ok false if semaphore
      semaphore++
    prop: nonce
  eq nonce, (new C())?.prop
  eq 1, semaphore

test "soaked function invocation safe on non-functions", ->
  eq undefined, (0)?(1)
  eq undefined, (0)? 1, 2

</script>
<script type="text/x-coffeescript" class="test" id="sourcemap">
return if global.testingBrowser

SourceMap = require '../src/sourcemap'

vlqEncodedValues = [
    [1, "C"],
    [-1, "D"],
    [2, "E"],
    [-2, "F"],
    [0, "A"],
    [16, "gB"],
    [948, "o7B"]
]

test "encodeVlq tests", ->
  for pair in vlqEncodedValues
    eq ((new SourceMap).encodeVlq pair[0]), pair[1]

test "SourceMap tests", ->
  map = new SourceMap
  map.add [0, 0], [0, 0]
  map.add [1, 5], [2, 4]
  map.add [1, 6], [2, 7]
  map.add [1, 9], [2, 8]
  map.add [3, 0], [3, 4]

  testWithFilenames = map.generate {
    sourceRoot: ""
    sourceFiles: ["source.coffee"]
    generatedFile: "source.js"
  }

  deepEqual testWithFilenames, {
    version: 3
    file: "source.js"
    sourceRoot: ""
    sources: ["source.coffee"]
    names: []
    mappings: "AAAA;;IACK,GAAC,CAAG;IAET"
  }

  deepEqual map.generate(), {
    version: 3
    file: ""
    sourceRoot: ""
    sources: [""]
    names: []
    mappings: "AAAA;;IACK,GAAC,CAAG;IAET"
  }

  # Look up a generated column - should get back the original source position.
  arrayEq map.sourceLocation([2,8]), [1,9]

  # Look up a point further along on the same line - should get back the same source position.
  arrayEq map.sourceLocation([2,10]), [1,9]

</script>
<script type="text/x-coffeescript" class="test" id="strict">
# Strict Early Errors
# -------------------

# The following are prohibited under ES5's `strict` mode
# * `Octal Integer Literals`
# * `Octal Escape Sequences`
# * duplicate property definitions in `Object Literal`s
# * duplicate formal parameter
# * `delete` operand is a variable
# * `delete` operand is a parameter
# * `delete` operand is `undefined`
# * `Future Reserved Word`s as identifiers: implements, interface, let, package, private, protected, public, static, yield
# * `eval` or `arguments` as `catch` identifier
# * `eval` or `arguments` as formal parameter
# * `eval` or `arguments` as function declaration identifier
# * `eval` or `arguments` as LHS of assignment
# * `eval` or `arguments` as the operand of a post/pre-fix inc/dec-rement expression

# helper to assert that code complies with strict prohibitions
strict = (code, msg) ->
  throws (-> CoffeeScript.compile code), null, msg ? code
strictOk = (code, msg) ->
  doesNotThrow (-> CoffeeScript.compile code), msg ? code


test "octal integer literals prohibited", ->
  strict    '01'
  strict    '07777'
  # decimals with a leading '0' are also prohibited
  strict    '09'
  strict    '079'
  strictOk  '`01`'

test "octal escape sequences prohibited", ->
  strict    '"\\1"'
  strict    '"\\7"'
  strict    '"\\001"'
  strict    '"\\777"'
  strict    '"_\\1"'
  strict    '"\\1_"'
  strict    '"_\\1_"'
  strict    '"\\\\\\1"'
  strictOk  '"\\0"'
  eq "\x00", "\0"
  strictOk  '"\\08"'
  eq "\x008", "\08"
  strictOk  '"\\0\\8"'
  eq "\x008", "\0\8"
  strictOk  '"\\8"'
  eq "8", "\8"
  strictOk  '"\\\\1"'
  eq "\\" + "1", "\\1"
  strictOk  '"\\\\\\\\1"'
  eq "\\\\" + "1", "\\\\1"
  strictOk  "`'\\1'`"
  eq "\\" + "1", `"\\1"`

  # Also test other string types.
  strict           "'\\\\\\1'"
  eq "\x008",      '\08'
  eq "\\\\" + "1", '\\\\1'
  strict           "'''\\\\\\1'''"
  eq "\x008",      '''\08'''
  eq "\\\\" + "1", '''\\\\1'''
  strict           '"""\\\\\\1"""'
  eq "\x008",      """\08"""
  eq "\\\\" + "1", """\\\\1"""

test "duplicate formal parameters are prohibited", ->
  nonce = {}
  # a Param can be an Identifier, ThisProperty( @-param ), Array, or Object
  # a Param can also be a splat (...) or an assignment (param=value)
  # the following function expressions should throw errors
  strict '(_,_)->',          'param, param'
  strict '(_,_...)->',       'param, param...'
  strict '(_,_ = true)->',   'param, param='
  strict '(@_,@_)->',        'two @params'
  strict '(@case,@case)->',  'two @reserved'
  strict '(_,{_})->',        'param, {param}'
  strict '(_,{_=true})->',   'param, {param=}'
  strict '({_,_})->',        '{param, param}'
  strict '({_=true,_})->',   '{param=, param}'
  strict '(_,[_])->',        'param, [param]'
  strict '(_,[_=true])->',   'param, [param=]'
  strict '([_,_])->',        '[param, param]'
  strict '([_=true,_])->',   '[param=, param]'
  strict '(_,[_]=true)->',   'param, [param]='
  strict '(_,[_=true]=true)->', 'param, [param=]='
  strict '(_,[@_,{_}])->',   'param, [@param, {param}]'
  strict '(_,[_,{@_}])->',   'param, [param, {@param}]'
  strict '(_,[_,{@_=true}])->', 'param, [param, {@param=}]'
  strict '(_,[_,{_}])->',    'param, [param, {param}]'
  strict '(_,[_,{__}])->',   'param, [param, {param2}]'
  strict '(_,[__,{_}])->',   'param, [param2, {param}]'
  strict '(__,[_,{_}])->',   'param, [param2, {param2}]'
  strict '({0:a,1:a})->',    '{0:param,1:param}'
  strict '(a=b=true,a)->',   'param=assignment, param'
  strict '({a=b=true},a)->', '{param=assignment}, param'
  # the following function expressions should **not** throw errors
  strictOk '(_,@_)->'
  strictOk '(@_,_...)->'
  strictOk '(_,@_ = true)->'
  strictOk '(@_,{_})->'
  strictOk '({_,@_})->'
  strictOk '({_,@_ = true})->'
  strictOk '([_,@_])->'
  strictOk '([_,@_ = true])->'
  strictOk '({},_arg)->'
  strictOk '({},{})->'
  strictOk '([]...,_arg)->'
  strictOk '({}...,_arg)->'
  strictOk '({}...,[],_arg)->'
  strictOk '([]...,{},_arg)->'
  strictOk '(@case,_case)->'
  strictOk '(@case,_case...)->'
  strictOk '(@case...,_case)->'
  strictOk '(_case,@case)->'
  strictOk '(_case,@case...)->'
  strictOk '({a:a})->'
  strictOk '({a:a,a:b})->'

test "`delete` operand restrictions", ->
  strict 'a = 1; delete a'
  strictOk 'delete a' #noop
  strict '(a) -> delete a'
  strict '(a...) -> delete a'
  strict '(a = 1) -> delete a'
  strict '([a]) -> delete a'
  strict '({a}) -> delete a'

test "`Future Reserved Word`s, `eval` and `arguments` restrictions", ->

  access = (keyword, check = strict) ->
    check "#{keyword}.a = 1"
    check "#{keyword}[0] = 1"
  assign = (keyword, check = strict) ->
    check "#{keyword} = 1"
    check "#{keyword} += 1"
    check "#{keyword} -= 1"
    check "#{keyword} *= 1"
    check "#{keyword} /= 1"
    check "#{keyword} ?= 1"
    check "#{keyword}++"
    check "++#{keyword}"
    check "#{keyword}--"
    check "--#{keyword}"
  destruct = (keyword, check = strict) ->
    check "{#{keyword}}"
    check "o = {#{keyword}}"
  invoke = (keyword, check = strict) ->
    check "#{keyword} yes"
    check "do #{keyword}"
  fnDecl = (keyword, check = strict) ->
    check "class #{keyword}"
  param = (keyword, check = strict) ->
    check "(#{keyword}) ->"
    check "({#{keyword}}) ->"
  prop = (keyword, check = strict) ->
    check "a.#{keyword} = 1"
  tryCatch = (keyword, check = strict) ->
    check "try new Error catch #{keyword}"

  future = 'implements interface let package private protected public static'.split ' '
  for keyword in future
    access   keyword
    assign   keyword
    destruct keyword
    invoke   keyword
    fnDecl   keyword
    param    keyword
    prop     keyword, strictOk
    tryCatch keyword

  for keyword in ['eval', 'arguments']
    access   keyword, strictOk
    assign   keyword
    destruct keyword, strictOk
    invoke   keyword, strictOk
    fnDecl   keyword
    param    keyword
    prop     keyword, strictOk
    tryCatch keyword

</script>
<script type="text/x-coffeescript" class="test" id="strings">
# String Literals
# ---------------

# TODO: refactor string literal tests
# TODO: add indexing and method invocation tests: "string"["toString"] is String::toString, "string".toString() is "string"

# * Strings
# * Heredocs

test "backslash escapes", ->
  eq "\\/\\\\", /\/\\/.source

eq '(((dollars)))', '\(\(\(dollars\)\)\)'
eq 'one two three', "one
 two
 three"
eq "four five", 'four

 five'

test "#3229, multiline strings", ->
  # Separate lines by default by a single space in literal strings.
  eq 'one
      two', 'one two'
  eq "one
      two", 'one two'
  eq '
        a
        b
    ', 'a b'
  eq "
        a
        b
    ", 'a b'
  eq 'one

        two', 'one two'
  eq "one

        two", 'one two'
  eq '
    indentation
      doesn\'t
  matter', 'indentation doesn\'t matter'
  eq 'trailing ws      
    doesn\'t matter', 'trailing ws doesn\'t matter'

  # Use backslashes at the end of a line to specify whitespace between lines.
  eq 'a \
      b\
      c  \
      d', 'a bc  d'
  eq "a \
      b\
      c  \
      d", 'a bc  d'
  eq 'ignore  \  
      trailing whitespace', 'ignore  trailing whitespace'

  # Backslash at the beginning of a literal string.
  eq '\
      ok', 'ok'
  eq '  \
      ok', '  ok'

  # #1273, empty strings.
  eq '\
     ', ''
  eq '
     ', ''
  eq '
          ', ''
  eq '   ', '   '

  # Same behavior in interpolated strings.
  eq "interpolation #{1}
      follows #{2}  \
      too #{3}\
      !", 'interpolation 1 follows 2  too 3!'
  eq "a #{
    'string ' + "inside
                 interpolation"
    }", "a string inside interpolation"
  eq "
      #{1}
     ", '1'

  # Handle escaped backslashes correctly.
  eq '\\', `'\\'`
  eq 'escaped backslash at EOL\\
      next line', 'escaped backslash at EOL\\ next line'
  eq '\\
      next line', '\\ next line'
  eq '\\
     ', '\\'
  eq '\\\\\\
     ', '\\\\\\'
  eq "#{1}\\
      after interpolation", '1\\ after interpolation'
  eq 'escaped backslash before slash\\  \
      next line', 'escaped backslash before slash\\  next line'
  eq 'triple backslash\\\
      next line', 'triple backslash\\next line'
  eq 'several escaped backslashes\\\\\\
      ok', 'several escaped backslashes\\\\\\ ok'
  eq 'several escaped backslashes slash\\\\\\\
      ok', 'several escaped backslashes slash\\\\\\ok'
  eq 'several escaped backslashes with trailing ws \\\\\\   
      ok', 'several escaped backslashes with trailing ws \\\\\\ ok'

  # Backslashes at beginning of lines.
  eq 'first line
      \   backslash at BOL', 'first line \   backslash at BOL'
  eq 'first line\
      \   backslash at BOL', 'first line\   backslash at BOL'

  # Backslashes at end of strings.
  eq 'first line \ ', 'first line  '
  eq 'first line
      second line \
      ', 'first line second line '
  eq 'first line
      second line
      \
      ', 'first line second line'
  eq 'first line
      second line

        \

      ', 'first line second line'

  # Edge case.
  eq 'lone

        \

        backslash', 'lone backslash'

test "#3249, escape newlines in heredocs with backslashes", ->
  # Ignore escaped newlines
  eq '''
    Set whitespace      \
       <- this is ignored\  
           none
      normal indentation
    ''', 'Set whitespace      <- this is ignorednone\n  normal indentation'
  eq """
    Set whitespace      \
       <- this is ignored\  
           none
      normal indentation
    """, 'Set whitespace      <- this is ignorednone\n  normal indentation'

  # Changed from #647, trailing backslash.
  eq '''
  Hello, World\

  ''', 'Hello, World'
  eq '''
    \\
  ''', '\\'

  # Backslash at the beginning of a literal string.
  eq '''\
      ok''', 'ok'
  eq '''  \
      ok''', '  ok'

  # Same behavior in interpolated strings.
  eq """
    interpolation #{1}
      follows #{2}  \
        too #{3}\
    !
  """, 'interpolation 1\n  follows 2  too 3!'
  eq """

    #{1} #{2}

    """, '\n1 2\n'

  # Handle escaped backslashes correctly.
  eq '''
    escaped backslash at EOL\\
      next line
  ''', 'escaped backslash at EOL\\\n  next line'
  eq '''\\

     ''', '\\\n'

  # Backslashes at beginning of lines.
  eq '''first line
      \   backslash at BOL''', 'first line\n\   backslash at BOL'
  eq """first line\
      \   backslash at BOL""", 'first line\   backslash at BOL'

  # Backslashes at end of strings.
  eq '''first line \ ''', 'first line  '
  eq '''
    first line
    second line \
  ''', 'first line\nsecond line '
  eq '''
    first line
    second line
    \
  ''', 'first line\nsecond line'
  eq '''
    first line
    second line

      \

  ''', 'first line\nsecond line\n'

  # Edge cases.
  eq '''lone

          \



        backslash''', 'lone\n\n  backslash'
  eq '''\
     ''', ''

test '#2388: `"""` in heredoc interpolations', ->
  eq """a heredoc #{
      "inside \
        interpolation"
    }""", "a heredoc inside interpolation"
  eq """a#{"""b"""}c""", 'abc'
  eq """#{""""""}""", ''

test "trailing whitespace", ->
  testTrailing = (str, expected) ->
    eq CoffeeScript.eval(str.replace /\|$/gm, ''), expected
  testTrailing '''"   |
      |
    a   |
           |
  "''', 'a'
  testTrailing """'''   |
      |
    a   |
           |
  '''""", '  \na   \n       '

#647
eq "''Hello, World\\''", '''
'\'Hello, World\\\''
'''
eq '""Hello, World\\""', """
"\"Hello, World\\\""
"""

test "#1273, escaping quotes at the end of heredocs.", ->
  # """\""" no longer compiles
  eq """\\""", '\\'
  eq """\\\"""", '\\\"'

a = """
    basic heredoc
    on two lines
    """
ok a is "basic heredoc\non two lines"

a = '''
    a
      "b
    c
    '''
ok a is "a\n  \"b\nc"

a = """
a
 b
  c
"""
ok a is "a\n b\n  c"

a = '''one-liner'''
ok a is 'one-liner'

a = """
      out
      here
"""
ok a is "out\nhere"

a = '''
       a
     b
   c
    '''
ok a is "    a\n  b\nc"

a = '''
a


b c
'''
ok a is "a\n\n\nb c"

a = '''more"than"one"quote'''
ok a is 'more"than"one"quote'

a = '''here's an apostrophe'''
ok a is "here's an apostrophe"

a = """""surrounded by two quotes"\""""
ok a is '""surrounded by two quotes""'

a = '''''surrounded by two apostrophes'\''''
ok a is "''surrounded by two apostrophes''"

# The indentation detector ignores blank lines without trailing whitespace
a = """
    one
    two

    """
ok a is "one\ntwo\n"

eq ''' line 0
  should not be relevant
    to the indent level
''', ' line 0\nshould not be relevant\n  to the indent level'

eq """
  interpolation #{
 "contents"
 }
  should not be relevant
    to the indent level
""", 'interpolation contents\nshould not be relevant\n  to the indent level'

eq ''' '\\\' ''', " '\\' "
eq """ "\\\" """, ' "\\" '

eq '''  <- keep these spaces ->  ''', '  <- keep these spaces ->  '

eq '''undefined''', 'undefined'
eq """undefined""", 'undefined'


test "#1046, empty string interpolations", ->
  eq "#{ }", ''

test "strings are not callable", ->
  throws -> CoffeeScript.compile '"a"()'
  throws -> CoffeeScript.compile '"a#{b}"()'
  throws -> CoffeeScript.compile '"a" 1'
  throws -> CoffeeScript.compile '"a#{b}" 1'
  throws -> CoffeeScript.compile '''
    "a"
       k: v
  '''
  throws -> CoffeeScript.compile '''
    "a#{b}"
       k: v
  '''

test "#3795: Escape otherwise invalid characters", ->
  eq ' ', '\u2028'
  eq ' ', '\u2029'
  eq '\0\
      1', '\x001'
  eq " ", '\u2028'
  eq " ", '\u2029'
  eq "\0\
      1", '\x001'
  eq ''' ''', '\u2028'
  eq ''' ''', '\u2029'
  eq '''\0\
      1''', '\x001'
  eq """ """, '\u2028'
  eq """ """, '\u2029'
  eq """\0\
      1""", '\x001'

  a = 'a'
  eq "#{a} ", 'a\u2028'
  eq "#{a} ", 'a\u2029'
  eq "#{a}\0\
      1", 'a\0' + '1'
  eq """#{a} """, 'a\u2028'
  eq """#{a} """, 'a\u2029'
  eq """#{a}\0\
      1""", 'a\0' + '1'

test "#4314: Whitespace less than or equal to stripped indentation", ->
  # The odd indentation is intentional here, to test 1-space indentation.
  eq ' ', """
 #{} #{}
"""

  eq '1 2  3   4    5     end\na 0     b', """
    #{1} #{2}  #{3}   #{4}    #{5}     end
    a #{0}     b"""

test "#4248: Unicode code point escapes", ->
  eq '\u01ab\u00cd', '\u{1ab}\u{cd}'
  eq '\u01ab', '\u{000001ab}'
  eq 'a\u01ab', "#{ 'a' }\u{1ab}"
  eq '\u01abc', '''\u{01ab}c'''
  eq '\u01abc', """\u{1ab}#{ 'c' }"""
  eq '\udab3\uddef', '\u{bcdef}'
  eq '\udab3\uddef', '\u{0000bcdef}'
  eq 'a\udab3\uddef', "#{ 'a' }\u{bcdef}"
  eq '\udab3\uddefc', '''\u{0bcdef}c'''
  eq '\udab3\uddefc', """\u{bcdef}#{ 'c' }"""
  eq '\\u{123456}', "#{'\\'}#{'u{123456}'}"

  # rewrite code point escapes
  input = """
    '\\u{bcdef}\\u{abc}'
    """
  output = """
    '\\udab3\\uddef\\u0abc';
  """
  eq toJS(input), output

  input = """
    "#{ 'a' }\\u{bcdef}"
    """
  output = """
    "a\\udab3\\uddef";
  """
  eq toJS(input), output

</script>
<script type="text/x-coffeescript" class="test" id="tagged_template_literals">
# Tagged template literals
# ------------------------

# NOTES:
# A tagged template literal is a string that is passed to a prefixing function for
# post-processing. There's a bunch of different angles that need testing:
# - Prefixing function, which can be any form of function call:
#   - function: func'Hello'
#   - object property with dot notation: outerobj.obj.func'Hello'
#   - object property with bracket notation: outerobj['obj']['func']'Hello'
# - String form: single quotes, double quotes and block strings
# - String is single-line or multi-line
# - String is interpolated or not

func = (text, expressions...) ->
  "text: [#{text.join '|'}] expressions: [#{expressions.join '|'}]"

outerobj =
  obj:
    func: func

# Example use
test "tagged template literal for html templating", ->
  html = (htmlFragments, expressions...) ->
    htmlFragments.reduce (fullHtml, htmlFragment, i) ->
      fullHtml + "#{expressions[i - 1]}#{htmlFragment}"

  state =
    name: 'Greg'
    adjective: 'awesome'

  eq """
      <p>
        Hi Greg. You're looking awesome!
      </p>
    """,
    html"""
      <p>
        Hi #{state.name}. You're looking #{state.adjective}!
      </p>
    """

# Simple, non-interpolated strings
test "tagged template literal with a single-line single-quote string", ->
  eq 'text: [single-line single quotes] expressions: []',
  func'single-line single quotes'

test "tagged template literal with a single-line double-quote string", ->
  eq 'text: [single-line double quotes] expressions: []',
  func"single-line double quotes"

test "tagged template literal with a single-line single-quote block string", ->
  eq 'text: [single-line block string] expressions: []',
  func'''single-line block string'''

test "tagged template literal with a single-line double-quote block string", ->
  eq 'text: [single-line block string] expressions: []',
  func"""single-line block string"""

test "tagged template literal with a multi-line single-quote string", ->
  eq 'text: [multi-line single quotes] expressions: []',
  func'multi-line
                                                              single quotes'

test "tagged template literal with a multi-line double-quote string", ->
  eq 'text: [multi-line double quotes] expressions: []',
  func"multi-line
       double quotes"

test "tagged template literal with a multi-line single-quote block string", ->
  eq 'text: [multi-line\nblock string] expressions: []',
  func'''
      multi-line
      block string
      '''

test "tagged template literal with a multi-line double-quote block string", ->
  eq 'text: [multi-line\nblock string] expressions: []',
  func"""
      multi-line
      block string
      """

# Interpolated strings with expressions
test "tagged template literal with a single-line double-quote interpolated string", ->
  eq 'text: [single-line | double quotes | interpolation] expressions: [36|42]',
  func"single-line #{6 * 6} double quotes #{6 * 7} interpolation"

test "tagged template literal with a single-line double-quote block interpolated string", ->
  eq 'text: [single-line | block string | interpolation] expressions: [incredible|48]',
  func"""single-line #{'incredible'} block string #{6 * 8} interpolation"""

test "tagged template literal with a multi-line double-quote interpolated string", ->
  eq 'text: [multi-line | double quotes | interpolation] expressions: [2|awesome]',
  func"multi-line #{4/2}
       double quotes #{'awesome'} interpolation"

test "tagged template literal with a multi-line double-quote block interpolated string", ->
  eq 'text: [multi-line |\nblock string |] expressions: [/abc/|32]',
  func"""
      multi-line #{/abc/}
      block string #{2 * 16}
      """


# Tagged template literal must use a callable function
test "tagged template literal dot notation recognized as a callable function", ->
  eq 'text: [dot notation] expressions: []',
  outerobj.obj.func'dot notation'

test "tagged template literal bracket notation recognized as a callable function", ->
  eq 'text: [bracket notation] expressions: []',
  outerobj['obj']['func']'bracket notation'

test "tagged template literal mixed dot and bracket notation recognized as a callable function", ->
  eq 'text: [mixed notation] expressions: []',
  outerobj['obj'].func'mixed notation'


# Edge cases
test "tagged template literal with an empty string", ->
  eq 'text: [] expressions: []',
  func''

test "tagged template literal with an empty interpolated string", ->
  eq 'text: [] expressions: []',
  func"#{}"

test "tagged template literal as single interpolated expression", ->
  eq 'text: [|] expressions: [3]',
  func"#{3}"

test "tagged template literal with an interpolated string that itself contains an interpolated string", ->
  eq 'text: [inner | string] expressions: [interpolated]',
  func"inner #{"#{'inter'}polated"} string"

test "tagged template literal with an interpolated string that contains a tagged template literal", ->
  eq 'text: [inner tagged | literal] expressions: [text: [|] expressions: [template]]',
  func"inner tagged #{func"#{'template'}"} literal"

test "tagged template literal with backticks", ->
  eq 'text: [ES template literals look like this: `foo bar`] expressions: []',
  func"ES template literals look like this: `foo bar`"

test "tagged template literal with escaped backticks", ->
  eq 'text: [ES template literals look like this: \\`foo bar\\`] expressions: []',
  func"ES template literals look like this: \\`foo bar\\`"

test "tagged template literal with unnecessarily escaped backticks", ->
  eq 'text: [ES template literals look like this: `foo bar`] expressions: []',
  func"ES template literals look like this: \`foo bar\`"

test "tagged template literal with ES interpolation", ->
  eq 'text: [ES template literals also look like this: `3 + 5 = ${3+5}`] expressions: []',
  func"ES template literals also look like this: `3 + 5 = ${3+5}`"

test "tagged template literal with both ES and CoffeeScript interpolation", ->
  eq "text: [ES template literals also look like this: `3 + 5 = ${3+5}` which equals |] expressions: [8]",
  func"ES template literals also look like this: `3 + 5 = ${3+5}` which equals #{3+5}"

test "tagged template literal with escaped ES interpolation", ->
  eq 'text: [ES template literals also look like this: `3 + 5 = \\${3+5}`] expressions: []',
  func"ES template literals also look like this: `3 + 5 = \\${3+5}`"

test "tagged template literal with unnecessarily escaped ES interpolation", ->
  eq 'text: [ES template literals also look like this: `3 + 5 = ${3+5}`] expressions: []',
  func"ES template literals also look like this: `3 + 5 = \${3+5}`"

test "tagged template literal special escaping", ->
  eq 'text: [` ` \\` \\` \\\\` $ { ${ ${ \\${ \\${ \\\\${ | ` ${] expressions: [1]',
  func"` \` \\` \\\` \\\\` $ { ${ \${ \\${ \\\${ \\\\${ #{1} ` ${"

</script>


</body>
</html>
